library(tidyverse)
library(readr)
library(lubridate)
library(stringr)

This is my lab notebook for the data analysis project where I will put to use the processes and tools I have found to do a complete data analysis start to finish.

There will be much trial and error and learning as I go. This notebook will be messy.

A few particularly important goals: 1. Define every step of the way, including any necessary steps to complete other steps. 2. Every single function or new idea that I put to use needs to be recorded in order to make flashcards. 3. Practice and formalize my iteration cycle.

My goal based iteration cycle is currently as follows: 1. Set a goal for the task ahead * Define expectations or criteria for success 2. Attempt to complete the goal or perform the task 3. Compare your results to your expectations or your criteria for success 4. (Optional) Use judgment and experience to decide whether you think the expectations should be altered, or the task should be repeated under different parameters 5. Make adjustments

The 5 Stages of Data Analysis: 1. Setting the Stage (get a better name) 2. EDA 3. Build models 4. Interpret and evaluate models 5. Communicate

Stage 1: Setting the Stage

Initial thoughts on what needs to be accomplished during this stage 1. Ask a question 2. Collect data 3. Inspect the data 4. Refine and sharpen the question 5. Clean and Tidy the data

It’s very important to note that interconnectedness between 1 and 2 above. In a formal setting, the analyst may be given a question to answer, then be tasked with collecting the data, or both may be given at the same time. In our informal, educational setting, we will choose the data first, then find an appropriate question.

I’m going to quickly run through my iteration cycle for finding a data set. 1. Set a goal for the task ahead * Define expectations or criteria for success The goal is to find a data set that from some private sector company that will lend itself well to questions about various performance factors

So I found some Kickstarter data. There are 40 something files, 20 mb each. Let’s start with the first one

So I need to inspect this dataset a little bit First I want to know the date range of this document That requires that I convert all of the dates into a usable format:

Next lets explore the date range. I’ll arbitrarily pick the launch dates to study

Interesting. That seems to go all the way until from 2009 until the date they were scraped.

I guess I’ll have to explore some other files. Perhaps this is a compilation or sample.

So let’s write a couple functions to import everything, then we’ll join the datasets and convert the dates

This is the one that worked:

Boom! Got it imported and combined! That pipe thing is kinda cool.

head(kickstarter)
n_distinct(kickstarter)
[1] 169832
dim(kickstarter)
[1] 169832     33
str(kickstarter)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   169832 obs. of  33 variables:
 $ id                    : int  946464764 432961380 886034377 1700257262 1291954177 773132137 1034315928 140043775 1822914340 1979668691 ...
 $ photo                 : chr  "{\"small\":\"https://ksr-ugc.imgix.net/assets/015/025/634/778323e325e49e1cf47cebc49e420b00_original.jpg?crop=faces&w=160&h=90&f"| __truncated__ "{\"small\":\"https://ksr-ugc.imgix.net/assets/015/085/011/0d25261525708ba220b7fdd31a00f2f4_original.jpg?crop=faces&w=160&h=90&f"| __truncated__ "{\"small\":\"https://ksr-ugc.imgix.net/assets/014/998/522/05acd2018b26a29145de61824c87ea3e_original.jpg?crop=faces&w=160&h=90&f"| __truncated__ "{\"small\":\"https://ksr-ugc.imgix.net/assets/015/134/849/c34df652ded9a0f1bacf900a36020e90_original.jpg?crop=faces&w=160&h=90&f"| __truncated__ ...
 $ name                  : chr  "100 Fantasy Portraits for Oria Trail the Game" "The Deer Hunter" "Bespoke Pet Portraits – Michael Gardner Design" "Ancient Ones: Knight of Jupiter" ...
 $ blurb                 : chr  "Get a fantasy portrait drawn of yourself, a loved one, a D&D or original character and have it added into a video game." "A series of digital paintings by Bryn G Jones" "My campaign is focused on creating bespoke pet portraits. I transform photos of loved pets into unique geometric portraits." "An introduction into the world of Ancient Ones, through the first Limited Edition print of the series, \"Knight of Jupiter\"." ...
 $ goal                  : num  100 25 500 200 1500 100 400 10000 3000 200 ...
 $ pledged               : num  478 294 501 893 1847 ...
 $ state                 : chr  "successful" "successful" "successful" "successful" ...
 $ slug                  : chr  "100-fantasy-portraits-for-oria-trail-the-game" "the-deer-hunter" "bespoke-pet-portraits-michael-gardner-design" "ancient-ones-knight-of-jupiter" ...
 $ disable_communication : chr  "false" "false" "false" "false" ...
 $ country               : chr  "US" "GB" "GB" "US" ...
 $ currency              : chr  "USD" "GBP" "GBP" "USD" ...
 $ currency_symbol       : chr  "$" "£" "£" "$" ...
 $ currency_trailing_code: chr  "true" "false" "false" "true" ...
 $ deadline              : int  1486194840 1485990000 1487101859 1487367219 1488040724 1488236400 1488405818 1488648406 1489684237 1491041571 ...
 $ state_changed_at      : int  1486194840 1485990001 1487101859 1487367221 1488040724 1488236400 1488405818 1488648408 1489684237 1491041571 ...
 $ created_at            : int  1483170863 1483733879 1482876950 1455213005 1470008219 1485572871 1479854987 1484917222 1486808780 1486396504 ...
 $ launched_at           : int  1483736396 1484479361 1484509859 1484775219 1485448724 1485617773 1485813818 1486056406 1487095837 1487157171 ...
 $ staff_pick            : chr  "false" "true" "false" "false" ...
 $ is_starrable          : chr  "false" "false" "false" "false" ...
 $ backers_count         : int  28 16 7 29 42 8 10 64 3 35 ...
 $ static_usd_rate       : num  1 1.22 1.22 1 1 ...
 $ usd_pledged           : num  478 358 610 893 1847 ...
 $ creator               : chr  "{\"urls\":{\"web\":{\"user\":\"https://www.kickstarter.com/profile/ithaqualabs\"},\"api\":{\"user\":\"https://api.kickstarter.c"| __truncated__ "{\"urls\":{\"web\":{\"user\":\"https://www.kickstarter.com/profile/1655679628\"},\"api\":{\"user\":\"https://api.kickstarter.co"| __truncated__ "{\"urls\":{\"web\":{\"user\":\"https://www.kickstarter.com/profile/346706187\"},\"api\":{\"user\":\"https://api.kickstarter.com"| __truncated__ "{\"urls\":{\"web\":{\"user\":\"https://www.kickstarter.com/profile/deadlastmedia\"},\"api\":{\"user\":\"https://api.kickstarter"| __truncated__ ...
 $ location              : chr  "{\"country\":\"US\",\"urls\":{\"web\":{\"discover\":\"https://www.kickstarter.com/discover/places/atlanta-ga\",\"location\":\"h"| __truncated__ "{\"country\":\"GB\",\"urls\":{\"web\":{\"discover\":\"https://www.kickstarter.com/discover/places/london-gb\",\"location\":\"ht"| __truncated__ "{\"country\":\"GB\",\"urls\":{\"web\":{\"discover\":\"https://www.kickstarter.com/discover/places/london-gb\",\"location\":\"ht"| __truncated__ "{\"country\":\"US\",\"urls\":{\"web\":{\"discover\":\"https://www.kickstarter.com/discover/places/chicago-il\",\"location\":\"h"| __truncated__ ...
 $ category              : chr  "{\"urls\":{\"web\":{\"discover\":\"http://www.kickstarter.com/discover/categories/art/digital%20art\"}},\"color\":16760235,\"pa"| __truncated__ "{\"urls\":{\"web\":{\"discover\":\"http://www.kickstarter.com/discover/categories/art/digital%20art\"}},\"color\":16760235,\"pa"| __truncated__ "{\"urls\":{\"web\":{\"discover\":\"http://www.kickstarter.com/discover/categories/art/digital%20art\"}},\"color\":16760235,\"pa"| __truncated__ "{\"urls\":{\"web\":{\"discover\":\"http://www.kickstarter.com/discover/categories/art/digital%20art\"}},\"color\":16760235,\"pa"| __truncated__ ...
 $ profile               : chr  "{\"background_image_opacity\":0.8,\"should_show_feature_image_section\":true,\"link_text_color\":null,\"state_changed_at\":1483"| __truncated__ "{\"background_image_opacity\":0.8,\"should_show_feature_image_section\":true,\"link_text_color\":null,\"state_changed_at\":1483"| __truncated__ "{\"background_image_opacity\":0.8,\"should_show_feature_image_section\":true,\"link_text_color\":null,\"state_changed_at\":1482"| __truncated__ "{\"background_image_opacity\":0.8,\"should_show_feature_image_section\":true,\"link_text_color\":\"\",\"state_changed_at\":1488"| __truncated__ ...
 $ spotlight             : chr  "true" "true" "true" "true" ...
 $ urls                  : chr  "{\"web\":{\"project\":\"https://www.kickstarter.com/projects/ithaqualabs/100-fantasy-portraits-for-oria-trail-the-game?ref=cate"| __truncated__ "{\"web\":{\"project\":\"https://www.kickstarter.com/projects/1655679628/the-deer-hunter?ref=category_newest\",\"rewards\":\"htt"| __truncated__ "{\"web\":{\"project\":\"https://www.kickstarter.com/projects/346706187/bespoke-pet-portraits-michael-gardner-design?ref=categor"| __truncated__ "{\"web\":{\"project\":\"https://www.kickstarter.com/projects/deadlastmedia/ancient-ones-knight-of-jupiter?ref=category_newest\""| __truncated__ ...
 $ source_url            : chr  "https://www.kickstarter.com/discover/categories/art/digital%20art?ref=category_modal&sort=magic" "https://www.kickstarter.com/discover/categories/art/digital%20art?ref=category_modal&sort=magic" "https://www.kickstarter.com/discover/categories/art/digital%20art?ref=category_modal&sort=magic" "https://www.kickstarter.com/discover/categories/art/digital%20art?ref=category_modal&sort=magic" ...
 $ friends               : chr  NA NA NA NA ...
 $ is_starred            : chr  NA NA NA NA ...
 $ is_backing            : chr  NA NA NA NA ...
 $ permissions           : chr  NA NA NA NA ...
colnames(kickstarter)
 [1] "id"                     "photo"                  "name"                  
 [4] "blurb"                  "goal"                   "pledged"               
 [7] "state"                  "slug"                   "disable_communication" 
[10] "country"                "currency"               "currency_symbol"       
[13] "currency_trailing_code" "deadline"               "state_changed_at"      
[16] "created_at"             "launched_at"            "staff_pick"            
[19] "is_starrable"           "backers_count"          "static_usd_rate"       
[22] "usd_pledged"            "creator"                "location"              
[25] "category"               "profile"                "spotlight"             
[28] "urls"                   "source_url"             "friends"               
[31] "is_starred"             "is_backing"             "permissions"           
names(kickstarter)
 [1] "id"                     "photo"                  "name"                  
 [4] "blurb"                  "goal"                   "pledged"               
 [7] "state"                  "slug"                   "disable_communication" 
[10] "country"                "currency"               "currency_symbol"       
[13] "currency_trailing_code" "deadline"               "state_changed_at"      
[16] "created_at"             "launched_at"            "staff_pick"            
[19] "is_starrable"           "backers_count"          "static_usd_rate"       
[22] "usd_pledged"            "creator"                "location"              
[25] "category"               "profile"                "spotlight"             
[28] "urls"                   "source_url"             "friends"               
[31] "is_starred"             "is_backing"             "permissions"           
summary(kickstarter)
       id               photo               name              blurb          
 Min.   :1.852e+04   Length:169832      Length:169832      Length:169832     
 1st Qu.:5.396e+08   Class :character   Class :character   Class :character  
 Median :1.079e+09   Mode  :character   Mode  :character   Mode  :character  
 Mean   :1.076e+09                                                           
 3rd Qu.:1.610e+09                                                           
 Max.   :2.147e+09                                                           
                                                                             
      goal              pledged            state               slug          
 Min.   :        0   Min.   :       0   Length:169832      Length:169832     
 1st Qu.:     2000   1st Qu.:      40   Class :character   Class :character  
 Median :     5000   Median :     900   Mode  :character   Mode  :character  
 Mean   :    51883   Mean   :   10566                                        
 3rd Qu.:    15000   3rd Qu.:    5100                                        
 Max.   :100000000   Max.   :13285226                                        
 NA's   :38                                                                  
 disable_communication   country            currency         currency_symbol   
 Length:169832         Length:169832      Length:169832      Length:169832     
 Class :character      Class :character   Class :character   Class :character  
 Mode  :character      Mode  :character   Mode  :character   Mode  :character  
                                                                               
                                                                               
                                                                               
                                                                               
 currency_trailing_code    deadline         state_changed_at      created_at       
 Length:169832          Min.   :1.241e+09   Min.   :1.241e+09   Min.   :1.240e+09  
 Class :character       1st Qu.:1.377e+09   1st Qu.:1.377e+09   1st Qu.:1.368e+09  
 Mode  :character       Median :1.424e+09   Median :1.424e+09   Median :1.417e+09  
                        Mean   :1.415e+09   Mean   :1.415e+09   Mean   :1.408e+09  
                        3rd Qu.:1.457e+09   3rd Qu.:1.457e+09   3rd Qu.:1.451e+09  
                        Max.   :1.508e+09   Max.   :1.503e+09   Max.   :1.503e+09  
                                                                                   
  launched_at         staff_pick        is_starrable       backers_count     
 Min.   :1.241e+09   Length:169832      Length:169832      Min.   :     0.0  
 1st Qu.:1.374e+09   Class :character   Class :character   1st Qu.:     2.0  
 Median :1.422e+09   Mode  :character   Mode  :character   Median :    16.0  
 Mean   :1.412e+09                                         Mean   :   122.9  
 3rd Qu.:1.454e+09                                         3rd Qu.:    68.0  
 Max.   :1.503e+09                                         Max.   :105857.0  
                                                                             
 static_usd_rate    usd_pledged         creator            location        
 Min.   :0.04564   Min.   :       0   Length:169832      Length:169832     
 1st Qu.:1.00000   1st Qu.:      39   Class :character   Class :character  
 Median :1.00000   Median :     900   Mode  :character   Mode  :character  
 Mean   :1.02256   Mean   :   10127                                        
 3rd Qu.:1.00000   3rd Qu.:    5073                                        
 Max.   :1.71641   Max.   :13285226                                        
                                                                           
   category           profile           spotlight             urls          
 Length:169832      Length:169832      Length:169832      Length:169832     
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
                                                                            
  source_url          friends           is_starred         is_backing       
 Length:169832      Length:169832      Length:169832      Length:169832     
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
                                                                            
 permissions       
 Length:169832     
 Class :character  
 Mode  :character  
                   
                   
                   
                   
summary(kickstarter[14:17])
    deadline         state_changed_at      created_at         launched_at       
 Min.   :1.241e+09   Min.   :1.241e+09   Min.   :1.240e+09   Min.   :1.241e+09  
 1st Qu.:1.377e+09   1st Qu.:1.377e+09   1st Qu.:1.368e+09   1st Qu.:1.374e+09  
 Median :1.424e+09   Median :1.424e+09   Median :1.417e+09   Median :1.422e+09  
 Mean   :1.415e+09   Mean   :1.415e+09   Mean   :1.408e+09   Mean   :1.412e+09  
 3rd Qu.:1.457e+09   3rd Qu.:1.457e+09   3rd Qu.:1.451e+09   3rd Qu.:1.454e+09  
 Max.   :1.508e+09   Max.   :1.503e+09   Max.   :1.503e+09   Max.   :1.503e+09  
format(object.size(kickstarter), units = "Mb")
[1] "701.5 Mb"
object.size(kickstarter)
735593520 bytes

SO that leaves us with a short list of useful tasks for inspecting the dataset: head() str() summary() dim() n_distinct() colnames() or names() object.size() # with format() and units arg

Convert state to a factor

is.factor(kickstarter$state)
[1] FALSE
kickstarter$state <- as.factor(kickstarter$state)
is.factor(kickstarter$state)
[1] TRUE

Convert dates

kickstarter$created_at <- as.POSIXct(as.numeric(kickstarter$created_at), origin = '1970-01-01', tz = 'GMT')
kickstarter$deadline <- as.POSIXct(as.numeric(kickstarter$deadline), origin = '1970-01-01', tz = 'GMT')
kickstarter$state_changed_at <- as.POSIXct(as.numeric(kickstarter$state_changed_at), origin = '1970-01-01', tz = 'GMT')
kickstarter$launched_at <- as.POSIXct(as.numeric(kickstarter$launched_at), origin = '1970-01-01', tz = 'GMT')
head(kickstarter)

Parse Dates

Maybe I don’t need to parse? Seems too easy…

kickstarter %>%
    arrange(launched_at) %>%
    summarise(min(launched_at), max(launched_at))
kickstarter %>%
    arrange(created_at) %>%
    summarise(min(created_at), max(created_at))

Normal time between creation and launch?

Back to my first iteration cycle: finding a dataset.

From earlier: I’m going to quickly run through my iteration cycle for finding a data set. 1. Set a goal for the task ahead * Define expectations or criteria for success The goal is to find a data set that from some private sector company that will lend itself well to questions about various performance factors

And a reminder of my iteration process: My goal based iteration cycle is currently as follows: 1. Set a goal for the task ahead * Define expectations or criteria for success 2. Attempt to complete the goal or perform the task 3. Compare your results to your expectations or your criteria for success 4. (Optional) Use judgment and experience to decide whether you think the expectations should be altered, or the task should be repeated under different parameters 5. Make adjustments

  1. Attempt to complete the goal or perform the task Done

  2. Compare your results to your expectations or your criteria for success Kickstarter data about potential startups was definitely not what I had in mind ( I was thinking more along the lines of a single private sector company)

  3. (Optional) Use judgment and experience to decide whether you think the expectations should be altered, or the task should be repeated under different parameters. My interpretation is that the expectations should be altered (and we should stick with the Kickstarter data)

And now let’s work on the question 1. Set a goal for the task ahead * Define expectations or criteria for success The goal is to have a question that will meet several criteria: 1. The answer may provide insight into factors that lead to successful funding on Kickstarter. 2. Can be answered with the current dataset. 3. Provides the opportunity to apply the Process of Data Science 4. Allows for exploration of the similarities and differences between Inferential and Predictive questions. The question should fall into one of the categories, but could be varied slightly to fall into the other for learning purposes. 5. Be sufficiently sharp to provide useful insight.

  1. Attempt to complete the goal or perform the task First pass: be very general. Attempt: What is the factor that best predicts successful funding on Kickstarter?

  2. Compare your results to your expectations or your criteria for success We’ll do this one by one.
  3. The answer may provide insight into factors that lead to successful funding on Kickstarter. -I think I’ve accomplished this one. If we answer the question, we would know about the factors that contribute to success. It feels its usefulness is limited by only looking for the single best variable. Perhaps we could change it to “factor or combination of factors”.

New question: What factor or combination of factors best predict successful funding on Kickstarter?

Now we’ll compare it to criteria #2. 2. Can be answered with the current dataset. -This one requires a little research and thought.

names(kickstarter)
 [1] "id"                     "photo"                  "name"                  
 [4] "blurb"                  "goal"                   "pledged"               
 [7] "state"                  "slug"                   "disable_communication" 
[10] "country"                "currency"               "currency_symbol"       
[13] "currency_trailing_code" "deadline"               "state_changed_at"      
[16] "created_at"             "launched_at"            "staff_pick"            
[19] "is_starrable"           "backers_count"          "static_usd_rate"       
[22] "usd_pledged"            "creator"                "location"              
[25] "category"               "profile"                "spotlight"             
[28] "urls"                   "source_url"             "friends"               
[31] "is_starred"             "is_backing"             "permissions"           

So what variables have any chance of being useful here? id-no photo-no name-possibly blurb-possibly goal-possibly pledged-possibly state-possibly slug-possibly disable_communication-possibly country-possibly currency-possibly currency_symbol-no currency_trailing_code-no deadline-possibly state_changed_at-possibly created_at-possibly launched_at–possibly staff_pick-possibly is_starrable-possibly backers_count-possibly static_usd_rate-no usd-pledged-possibly creator-possibly location-possibly category-possibly profile-possibly spotlight-possibly urls-no source-url friends-possibly is_starred-possibly is_backing-possibly permissions-possibly

So a lot of those will require more info about what each of those variables actually contain. We can go look, but right now we just need a rough idea about whether or not we have a chance of answering the question. We can explore what information each of those variables contains in the next stage (EDA).

And on to criteria #3: 3. Provides the opportunity to apply the Process of Data Science Since we have nearly completed stage 1, lets walk through the next 4 stages, simply deciding whether we are likely or not to be able to use this question at each stage Stage 2: EDA - yes Stage 3: Build a model - yes Stage 4: Interpret the results - yes Stage 5: Communicate - yes Overall: yes

Criteria 4: 4. Allows for exploration of the similarities and differences between Inferential and Predictive questions. The question should fall into one of the categories, but could be varied slightly to fall into the other for learning purposes. -This one requires a few definitions: An inferential data analysis quantifies whether an observed pattern will likely hold beyond the data set in hand.

Going beyond an inferential data analysis, which quantifies the relationships at population scale, a predictive data analysis uses a subset of measurements (the features) to predict another measurement (the outcome) on a single person or unit.

Shit - I just realized something. As its phrased, I would be trying to perform classification, rather than regression with a continuous outcome. Hmmmm. Is there a variable I could use as an outcome that is continuous? pledged, backers_count, or (mutated) pledged as a percentage of goal. I tlike the pledged as a percentage of goal because it gives degrees of success, instead of just binary. Otherwise, barely failed and really failed would be treated the same. Similarly, barely failed and barely succeeded would be treated as completely different. Ok I like that. Crisis averted. I could also use the binary version as a means of comparison, and simply to show another type of model.

So back to inferential v predictive, as originally phrased, it is a predictive question. This is more useful than attempting to determine whether or not it would hold at the population scale. We can stick with prediction, but show how to use inferential statistics when necessary.

And finally, criteria #5: 5. Be sufficiently sharp to provide useful insight. As it stands, it is not sharp. However, we can sharpen as necessary. We can put together sharper questions in order to test our models (hypotheses). -I might take this one out.

We could also compare to AoDS criteria: Characteristics of a Good Question: 1. Should be of interest to your audience 2. Should not have already been answered 3. Should stem from a plausible framework 4. Should be answerable 5. Specificity

But that sounds a little boring…

I think I have sufficiently met my criteria after the one iteration. Almost too easy.

It’s worth discussing how this process continues through (at least) the next two stages. The purpose of EDA is to explore the variables, identify relationships, and generate ideas to test further. We will come up with more specific questions to test later. Specificity will increase to the point of becoming a hypothesis (or pair of hypotheses).

So onto some cleaning and tidying.

Let’s first compare to tidy principles: 1. Each variable forms a column. 2. Each observation forms a row. 3. Each type of observational unit forms a table

We’re actually pretty tidy already. When I go back through, I should find some messy datasets and perform some basic tidying.

Other common data cleaning tasks: outlier checking date parsing missing value imputation

I think I took care of the date parsing, right? When I converted from unix, they were already parsed. But lets get a definition.

So let’s start checking for and playing with missing data. BLAAAAHHHH

kickstarter[!complete.cases(kickstarter),]
kickstarter[complete.cases(kickstarter),]
options(scipen = 999)
colMeans(is.na(kickstarter))
                    id                  photo                   name 
        0.000000000000         0.000000000000         0.000005888172 
                 blurb                   goal                pledged 
        0.000017664516         0.000223750530         0.000000000000 
                 state                   slug  disable_communication 
        0.000000000000         0.000000000000         0.000000000000 
               country               currency        currency_symbol 
        0.000000000000         0.000000000000         0.000000000000 
currency_trailing_code               deadline       state_changed_at 
        0.000000000000         0.000000000000         0.000000000000 
            created_at            launched_at             staff_pick 
        0.000000000000         0.000000000000         0.000000000000 
          is_starrable          backers_count        static_usd_rate 
        0.000000000000         0.000000000000         0.000000000000 
           usd_pledged                creator               location 
        0.000000000000         0.000000000000         0.004316029959 
              category                profile              spotlight 
        0.000000000000         0.000000000000         0.000000000000 
                  urls             source_url                friends 
        0.000000000000         0.000000000000         0.999735032267 
            is_starred             is_backing            permissions 
        0.999735032267         0.999735032267         0.999735032267 
head(kickstarter[30:33], 100)
nrow(kickstarter) * mean(is.na(kickstarter$location))
[1] 733
sum(is.na(kickstarter$location))
[1] 733

So what other tasks should I introduce as data cleaning? Parse dates Manipulate strings? Convert to factors? Mutate? Check for outliers? Or wait until EDA?

kickstarter %>%
    summarise(max(pledged))

This should be done visually

ggplot(kickstarter, aes(state, pledged)) + 
    geom_boxplot()

kickstarter %>%
    filter(pledged > 7500000) 
kickstarter %>%
    arrange(desc(pledged))
kickstarter %>%
    group_by(state) %>%
    summarise(n(), mean(pledged))

We should probably remove live entries since they are not complete.

Since live would indicate a deadline of after 8/15/17, let’s see if we can see how many there are, and compare to those with the live state.

kickstarter %>%
    filter(deadline >= ymd("2017-08-15")) %>%
        group_by(state) %>%
     summarise(n(), mean(pledged))

So some may have been suspended or cancelled, or also reached their goal before the data was scraped. But the vast majority are live. We could check that the other way as well, just to be sure we know what we’re working with.

kickstarter %>%
    filter(deadline <= ymd("2017-08-15")) %>%
        group_by(state) %>%
     summarise(n(), mean(pledged))

Confirmed my suspicion that live records are just ones that haven’t met their deadline as of the time they were scraped. We should remove them.

169832-3573
[1] 166259
kickstarter <- kickstarter %>%
    filter(state != "live")
nrow(kickstarter)
[1] 166259

Is the data tidy? Hadley’s Definition of Tidy Data: 1. Each variable forms a column. 2. Each observation forms a row. 3. Each type of observational unit forms a table

Yes we are pretty much tidy. When i come back through here, I need to come up with (randomly construct) an untidy dataset, and perform some common operations on it.

A little more cleaning I could do is remove some uneccesary columns to make things a little easier to see and work with. Let’s revisit a couple things.

head(kickstarter)

Some possible columns to remove: photo friends is_starred is_backing permissions

A few need to be made to factors: disable_communication country currency currency_symbol currency_trailing_code staff_pick is_starrable spotlight

Let’s make the factors real quickly

kickstarter$state <- as.factor(kickstarter$state)
kickstarter$disable_communication <- as.factor(kickstarter$disable_communication)
kickstarter$country <- as.factor(kickstarter$country)
kickstarter$currency <- as.factor(kickstarter$currency)
kickstarter$currency_symbol <- as.factor(kickstarter$currency_symbol)
kickstarter$currency_trailing_code <- as.factor(kickstarter$currency_trailing_code)
kickstarter$staff_pick <- as.factor(kickstarter$staff_pick)
kickstarter$is_starrable <- as.factor(kickstarter$is_starrable)
kickstarter$spotlight <- as.factor(kickstarter$spotlight)
names(kickstarter)
 [1] "id"                     "photo"                  "name"                  
 [4] "blurb"                  "goal"                   "pledged"               
 [7] "state"                  "slug"                   "disable_communication" 
[10] "country"                "currency"               "currency_symbol"       
[13] "currency_trailing_code" "deadline"               "state_changed_at"      
[16] "created_at"             "launched_at"            "staff_pick"            
[19] "is_starrable"           "backers_count"          "static_usd_rate"       
[22] "usd_pledged"            "creator"                "location"              
[25] "category"               "profile"                "spotlight"             
[28] "urls"                   "source_url"             "friends"               
[31] "is_starred"             "is_backing"             "permissions"           
summary(kickstarter)
       id                photo               name              blurb          
 Min.   :     18520   Length:166259      Length:166259      Length:166259     
 1st Qu.: 540413859   Class :character   Class :character   Class :character  
 Median :1079698068   Mode  :character   Mode  :character   Mode  :character  
 Mean   :1076278785                                                           
 3rd Qu.:1609983854                                                           
 Max.   :2147476221                                                           
                                                                              
      goal              pledged                state           slug          
 Min.   :        0   Min.   :       0   canceled  :11090   Length:166259     
 1st Qu.:     2000   1st Qu.:      40   failed    :78341   Class :character  
 Median :     5000   Median :     912   live      :    0   Mode  :character  
 Mean   :    50583   Mean   :   10546   successful:76055                     
 3rd Qu.:    15000   3rd Qu.:    5118   suspended :  773                     
 Max.   :100000000   Max.   :13285226                                        
 NA's   :38                                                                  
 disable_communication    country          currency      currency_symbol
 false:165486          US     :130797   USD    :130797   $ :142428      
 true :   773          GB     : 14543   GBP    : 14543   £ : 14543      
                       CA     :  6612   EUR    :  7256   € :  7256      
                       AU     :  3518   CAD    :  6612   Fr:   317      
                       DE     :  1686   AUD    :  3518   kr:  1715      
                       NL     :  1369   SEK    :   810                  
                       (Other):  7734   (Other):  2723                  
 currency_trailing_code    deadline                   state_changed_at             
 false: 22116           Min.   :2009-05-03 06:59:59   Min.   :2009-05-03 07:00:17  
 true :144143           1st Qu.:2013-07-26 12:27:48   1st Qu.:2013-07-26 01:14:34  
                        Median :2015-02-01 17:55:25   Median :2015-01-31 01:00:13  
                        Mean   :2014-10-10 03:42:29   Mean   :2014-10-08 16:03:35  
                        3rd Qu.:2016-02-04 14:05:14   3rd Qu.:2016-02-02 09:39:32  
                        Max.   :2017-10-12 19:39:05   Max.   :2017-08-16 04:28:24  
                                                                                   
   created_at                   launched_at                  staff_pick    
 Min.   :2009-04-21 17:35:35   Min.   :2009-04-24 19:52:03   false:147109  
 1st Qu.:2013-04-23 16:17:08   1st Qu.:2013-06-25 00:41:18   true : 19150  
 Median :2014-11-05 08:54:38   Median :2014-12-30 19:37:23                 
 Mean   :2014-07-27 13:05:53   Mean   :2014-09-06 07:05:32                 
 3rd Qu.:2015-11-16 19:29:57   3rd Qu.:2016-01-02 21:44:01                 
 Max.   :2017-08-15 17:08:05   Max.   :2017-08-15 18:23:44                 
                                                                           
 is_starrable   backers_count      static_usd_rate    usd_pledged      
 false:166259   Min.   :     0.0   Min.   :0.04564   Min.   :       0  
                1st Qu.:     2.0   1st Qu.:1.00000   1st Qu.:      40  
                Median :    17.0   Median :1.00000   Median :     914  
                Mean   :   123.5   Mean   :1.02371   Mean   :   10166  
                3rd Qu.:    69.0   3rd Qu.:1.00000   3rd Qu.:    5100  
                Max.   :105857.0   Max.   :1.71641   Max.   :13285226  
                                                                       
   creator            location           category           profile         
 Length:166259      Length:166259      Length:166259      Length:166259     
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
                                                                            
 spotlight         urls            source_url          friends         
 false:90204   Length:166259      Length:166259      Length:166259     
 true :76055   Class :character   Class :character   Class :character  
               Mode  :character   Mode  :character   Mode  :character  
                                                                       
                                                                       
                                                                       
                                                                       
  is_starred         is_backing        permissions       
 Length:166259      Length:166259      Length:166259     
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
                                                         

Some possible columns to remove: photo friends is_starred is_backing permissions

kickstarter <- kickstarter %>%
    select(-c(photo, friends, is_starred, is_backing, permissions))
dim(kickstarter)
[1] 166259     28

Let’s also remove profile

kickstarter <- kickstarter %>%
    select(-profile)
dim(kickstarter)
[1] 166259     27
head(kickstarter)

https://www.kickstarter.com/discover/categories/art/digital%20art?ref=category_modal&sort=magic {“web”:{“project”:“https://www.kickstarter.com/projects/ithaqualabs/100-fantasy-portraits-for-oria-trail-the-game?ref=category_newest”,“rewards”:“https://www.kickstarter.com/projects/ithaqualabs/100-fantasy-portraits-for-oria-trail-the-game/rewards”}}

Remove urls

kickstarter <- kickstarter %>%
    select(-urls)
dim(kickstarter)
[1] 166259     26
head(kickstarter)

And a few that could use some string manipulation: creator location category profile

kickstarter %>%
    select(category)

{“urls”:{“web”:{“discover”:“http://www.kickstarter.com/discover/categories/art/digital%20art”}},“color”:16760235,“parent_id”:1,“name”:“Digital Art”,“id”:21,“position”:3,“slug”:“art/digital art”}

{“urls”:{“web”:{“discover”:“http://www.kickstarter.com/discover/categories/art/illustration”}},“color”:16760235,“parent_id”:1,“name”:“Illustration”,“id”:22,“position”:4,“slug”:“art/illustration”}

length(levels(as.factor(kickstarter$category)))
[1] 154

Let’s experiment

extract_category <- function(string) {
    output <- vector("character", length(string))
    start <- '"name":"'
    end <- '"id"'
    for (i in seq_along(string)) {
        loc_start <- str_locate(string[[i]], start) 
        loc_end <- str_locate(string[[i]], end)
        output[[i]] <- str_sub(string[[i]], 
                               (loc_start[1,1] + 8), 
                               (loc_end[1,1] - 3)
                               )
    }
   output
}
kickstarter$category <- extract_category(kickstarter$category)

Extract creator {“urls”:{“web”:{“user”:“https://www.kickstarter.com/profile/ithaqualabs”},“api”:{“user”:“https://api.kickstarter.com/v1/users/246410818?signature=1502949105.be71a5c8169617f9faeec39b384b715b0dcbbdcd”}},“is_registered”:true,“name”:“Christopher \”Michael\" Hall“,”id“:246410818,”avatar“:{”small“:”https://ksr-ugc.imgix.net/assets/007/018/494/e96cc66ca639dfc9055df48505952104_original.jpg?w=160&h=160&fit=crop&v=1461428617&auto=format&q=92&s=947233770a463f383a6e02ce9de927ab“,”thumb“:”https://ksr-ugc.imgix.net/assets/007/018/494/e96cc66ca639dfc9055df48505952104_original.jpg?w=40&h=40&fit=crop&v=1461428617&auto=format&q=92&s=2235a24568ec8aadb35373184933a347“,”medium“:”https://ksr-ugc.imgix.net/assets/007/018/494/e96cc66ca639dfc9055df48505952104_original.jpg?w=160&h=160&fit=crop&v=1461428617&auto=format&q=92&s=947233770a463f383a6e02ce9de927ab“},”slug“:”ithaqualabs“}

extract_creator <- function(string) {
    output <- vector("character", length(string))
    start <- '"name":"'
    end <- '"id"'
    for (i in seq_along(string)) {
        loc_start <- str_locate(string[[i]], start) 
        loc_end <- str_locate(string[[i]], end)
        output[[i]] <- str_sub(string[[i]], 
                               (loc_start[1,1] + 8), 
                               (loc_end[1,1] - 3)
                               )
    }
   output
}
kickstarter$creator <- extract_creator(kickstarter$creator)
kickstarter %>%
    select(creator)

Extract location {“country”:“US”,“urls”:{“web”:{“discover”:“https://www.kickstarter.com/discover/places/atlanta-ga”,“location”:“https://www.kickstarter.com/locations/atlanta-ga”},“api”:{“nearby_projects”:“https://api.kickstarter.com/v1/discover?signature=1502924597.cb3fbf5fbe9154ddf04d85e7be879e4403e3fd98&woe_id=2357024”}},“name”:“Atlanta”,“displayable_name”:“Atlanta, GA”,“short_name”:“Atlanta, GA”,“id”:2357024,“state”:“GA”,“type”:“Town”,“is_root”:false,“slug”:“atlanta-ga”}

extract_location <- function(string) {
    output <- vector("character", length(string))
    start <- '"displayable_name":"'
    end <- '"short_name"'
    for (i in seq_along(string)) {
        loc_start <- str_locate(string[[i]], start) 
        loc_end <- str_locate(string[[i]], end)
        output[[i]] <- str_sub(string[[i]], 
                               (loc_start[1,1] + 20), 
                               (loc_end[1,1] - 3)
                               )
    }
   output
}
kickstarter$location <- extract_location(kickstarter$location)
kickstarter %>%
    select(location)

Extract profile - Nevermind, get rid of it! {“background_image_opacity”:0.8,“should_show_feature_image_section”:true,“link_text_color”:null,“state_changed_at”:1483170864,“blurb”:null,“background_color”:null,“project_id”:2816416,“name”:null,“feature_image_attributes”:{“image_urls”:{“default”:“https://ksr-ugc.imgix.net/assets/015/025/634/778323e325e49e1cf47cebc49e420b00_original.jpg?crop=faces&w=1552&h=873&fit=crop&v=1483175120&auto=format&q=92&s=9dfd6c8242477cf82c8e8c03d0801a45”,“baseball_card”:“https://ksr-ugc.imgix.net/assets/015/025/634/778323e325e49e1cf47cebc49e420b00_original.jpg?crop=faces&w=560&h=315&fit=crop&v=1483175120&auto=format&q=92&s=28ca75d75ac91e75cbbdcddfa2c6042e”}},“link_url”:null,“show_feature_image”:false,“id”:2816416,“state”:“inactive”,“text_color”:null,“link_text”:null,“link_background_color”:null}

And now convert a couple of those recently extracted character strings to factors

kickstarter$category <- as.factor(kickstarter$category)
kickstarter$location <- as.factor(kickstarter$location)
kickstarter$id <- as.character(kickstarter$id)
summary(kickstarter)
      id                name              blurb                goal          
 Length:166259      Length:166259      Length:166259      Min.   :        0  
 Class :character   Class :character   Class :character   1st Qu.:     2000  
 Mode  :character   Mode  :character   Mode  :character   Median :     5000  
                                                          Mean   :    50583  
                                                          3rd Qu.:    15000  
                                                          Max.   :100000000  
                                                          NA's   :38         
    pledged                state           slug           disable_communication
 Min.   :       0   canceled  :11090   Length:166259      false:165486         
 1st Qu.:      40   failed    :78341   Class :character   true :   773         
 Median :     912   live      :    0   Mode  :character                        
 Mean   :   10546   successful:76055                                           
 3rd Qu.:    5118   suspended :  773                                           
 Max.   :13285226                                                              
                                                                               
    country          currency      currency_symbol currency_trailing_code
 US     :130797   USD    :130797   $ :142428       false: 22116          
 GB     : 14543   GBP    : 14543   £ : 14543       true :144143          
 CA     :  6612   EUR    :  7256   € :  7256                             
 AU     :  3518   CAD    :  6612   Fr:   317                             
 DE     :  1686   AUD    :  3518   kr:  1715                             
 NL     :  1369   SEK    :   810                                         
 (Other):  7734   (Other):  2723                                         
    deadline                   state_changed_at             
 Min.   :2009-05-03 06:59:59   Min.   :2009-05-03 07:00:17  
 1st Qu.:2013-07-26 12:27:48   1st Qu.:2013-07-26 01:14:34  
 Median :2015-02-01 17:55:25   Median :2015-01-31 01:00:13  
 Mean   :2014-10-10 03:42:29   Mean   :2014-10-08 16:03:35  
 3rd Qu.:2016-02-04 14:05:14   3rd Qu.:2016-02-02 09:39:32  
 Max.   :2017-10-12 19:39:05   Max.   :2017-08-16 04:28:24  
                                                            
   created_at                   launched_at                  staff_pick    
 Min.   :2009-04-21 17:35:35   Min.   :2009-04-24 19:52:03   false:147109  
 1st Qu.:2013-04-23 16:17:08   1st Qu.:2013-06-25 00:41:18   true : 19150  
 Median :2014-11-05 08:54:38   Median :2014-12-30 19:37:23                 
 Mean   :2014-07-27 13:05:53   Mean   :2014-09-06 07:05:32                 
 3rd Qu.:2015-11-16 19:29:57   3rd Qu.:2016-01-02 21:44:01                 
 Max.   :2017-08-15 17:08:05   Max.   :2017-08-15 18:23:44                 
                                                                           
 is_starrable   backers_count      static_usd_rate    usd_pledged      
 false:166259   Min.   :     0.0   Min.   :0.04564   Min.   :       0  
                1st Qu.:     2.0   1st Qu.:1.00000   1st Qu.:      40  
                Median :    17.0   Median :1.00000   Median :     914  
                Mean   :   123.5   Mean   :1.02371   Mean   :   10166  
                3rd Qu.:    69.0   3rd Qu.:1.00000   3rd Qu.:    5100  
                Max.   :105857.0   Max.   :1.71641   Max.   :13285226  
                                                                       
   creator                       location                category      spotlight    
 Length:166259      Los Angeles, CA  :  8705   Web           :  4106   false:90204  
 Class :character   New York, NY     :  6679   Narrative Film:  2987   true :76055  
 Mode  :character   London, UK       :  4872   Public Art    :  2981                
                    Chicago, IL      :  3353   Indie Rock    :  2975                
                    San Francisco, CA:  3044   Painting      :  2969                
                    (Other)          :138873   Pop           :  2969                
                    NA's             :   733   (Other)       :147272                
  source_url       
 Length:166259     
 Class :character  
 Mode  :character  
                   
                   
                   
                   

So I want to run back through what I did in stage 1, which I feel I have now completed. A couple levels to focus on: Top level: I think I stuck with the basic activities that I started with, but I will verify that. Second level: I think they were all pretty straight forward, except for the cleaning part. I want to be sure and outline all of the things I did for cleaning so that I can generalize a little bit. And I want to be sure that I did in fact complete the other stages. I also want to see if there were any steps worth listing for any of those. Also, would anything have benefitted from a more formal walk through the iteration process?

To begin: My initial goals for things to accomplish in Stage 1: Initial thoughts on what needs to be accomplished during this stage 1. Ask a question 2. Collect data 3. Inspect the data 4. Refine and sharpen the question (not really a distinct stop - encompassed in the iteration cycle) 5. Clean and Tidy the data

Inspect: head n_distinct dim str colnames/names summary object.size Plotted some dates Some grouped summaries

Clean and Tidy: Converted Dates Characters to factors Check for and deal with missing data Explore and deal with outliers Remove unnecessary data (generalized from useless columns and live/ongoing cases) Manipulate character strings

So I think that the inspect steps and the clean/tidy step could really benefit from a stated goal at the beginning. This would allow use of the iteration cycle and more clearly define the work to be done.

Goal for Inspect: To develop an idea of the potential usefulness of the dataset and identify problems with the dataset.

Goal for Clean and Tidy: To put the dataset into a useful format and fix problems with the dataset.

I like it. I could revisit these on the next pass.

So should I go with a different notebook for the next stage? Nah

Stage 2: Exploratory Data Analysis (EDA)

LS0tCnRpdGxlOiAicnBhcG9kYTEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KYGBge3IgUGFja2FnZXN9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShzdHJpbmdyKQoKYGBgCgpUaGlzIGlzIG15IGxhYiBub3RlYm9vayBmb3IgdGhlIGRhdGEgYW5hbHlzaXMgcHJvamVjdCB3aGVyZSBJIHdpbGwgcHV0IHRvIHVzZQp0aGUgcHJvY2Vzc2VzIGFuZCB0b29scyBJIGhhdmUgZm91bmQgdG8gZG8gYSBjb21wbGV0ZSBkYXRhIGFuYWx5c2lzIHN0YXJ0IHRvIGZpbmlzaC4KClRoZXJlIHdpbGwgYmUgbXVjaCB0cmlhbCBhbmQgZXJyb3IgYW5kIGxlYXJuaW5nIGFzIEkgZ28uIFRoaXMgbm90ZWJvb2sgd2lsbCBiZSBtZXNzeS4KCkEgZmV3IHBhcnRpY3VsYXJseSBpbXBvcnRhbnQgZ29hbHM6CjEuIERlZmluZSBldmVyeSBzdGVwIG9mIHRoZSB3YXksIGluY2x1ZGluZyBhbnkgbmVjZXNzYXJ5IHN0ZXBzIHRvIGNvbXBsZXRlIG90aGVyIHN0ZXBzLgoyLiBFdmVyeSBzaW5nbGUgZnVuY3Rpb24gb3IgbmV3IGlkZWEgdGhhdCBJIHB1dCB0byB1c2UgbmVlZHMgdG8gYmUgcmVjb3JkZWQgaW4gb3JkZXIgdG8gCm1ha2UgZmxhc2hjYXJkcy4KMy4gUHJhY3RpY2UgYW5kIGZvcm1hbGl6ZSBteSBpdGVyYXRpb24gY3ljbGUuCgpNeSBnb2FsIGJhc2VkIGl0ZXJhdGlvbiBjeWNsZSBpcyBjdXJyZW50bHkgYXMgZm9sbG93czoKMS4gU2V0IGEgZ29hbCBmb3IgdGhlIHRhc2sgYWhlYWQKKiBEZWZpbmUgZXhwZWN0YXRpb25zIG9yIGNyaXRlcmlhIGZvciBzdWNjZXNzCjIuIEF0dGVtcHQgdG8gY29tcGxldGUgdGhlIGdvYWwgb3IgcGVyZm9ybSB0aGUgdGFzawozLiBDb21wYXJlIHlvdXIgcmVzdWx0cyB0byB5b3VyIGV4cGVjdGF0aW9ucyBvciB5b3VyIGNyaXRlcmlhIGZvciBzdWNjZXNzCjQuIChPcHRpb25hbCkgVXNlIGp1ZGdtZW50IGFuZCBleHBlcmllbmNlIHRvIGRlY2lkZSB3aGV0aGVyIHlvdSB0aGluayB0aGUgZXhwZWN0YXRpb25zIHNob3VsZCBiZSBhbHRlcmVkLCBvciB0aGUgdGFzayBzaG91bGQgYmUgcmVwZWF0ZWQgdW5kZXIgZGlmZmVyZW50IHBhcmFtZXRlcnMKNS4gTWFrZSBhZGp1c3RtZW50cwoKCgoKVGhlIDUgU3RhZ2VzIG9mIERhdGEgQW5hbHlzaXM6CjEuIFNldHRpbmcgdGhlIFN0YWdlIChnZXQgYSBiZXR0ZXIgbmFtZSkKMi4gRURBCjMuIEJ1aWxkIG1vZGVscwo0LiBJbnRlcnByZXQgYW5kIGV2YWx1YXRlIG1vZGVscwo1LiBDb21tdW5pY2F0ZQoKIyMgU3RhZ2UgMTogU2V0dGluZyB0aGUgU3RhZ2UKPCEtLSBJIGdvdHRhIGdldCBhIGJldHRlciBuYW1lIGZvciB0aGF0ICAtLT4KCkluaXRpYWwgdGhvdWdodHMgb24gd2hhdCBuZWVkcyB0byBiZSBhY2NvbXBsaXNoZWQgZHVyaW5nIHRoaXMgc3RhZ2UKMS4gQXNrIGEgcXVlc3Rpb24KMi4gQ29sbGVjdCBkYXRhCjMuIEluc3BlY3QgdGhlIGRhdGEKNC4gUmVmaW5lIGFuZCBzaGFycGVuIHRoZSBxdWVzdGlvbgo1LiBDbGVhbiBhbmQgVGlkeSB0aGUgZGF0YQoKSXQncyB2ZXJ5IGltcG9ydGFudCB0byBub3RlIHRoYXQgaW50ZXJjb25uZWN0ZWRuZXNzIGJldHdlZW4gMSBhbmQgMiBhYm92ZS4gSW4gYSAKZm9ybWFsIHNldHRpbmcsIHRoZSBhbmFseXN0IG1heSBiZSBnaXZlbiBhIHF1ZXN0aW9uIHRvIGFuc3dlciwgdGhlbiBiZSB0YXNrZWQgd2l0aCAKY29sbGVjdGluZyB0aGUgZGF0YSwgb3IgYm90aCBtYXkgYmUgZ2l2ZW4gYXQgdGhlIHNhbWUgdGltZS4gSW4gb3VyIGluZm9ybWFsLCBlZHVjYXRpb25hbApzZXR0aW5nLCB3ZSB3aWxsIGNob29zZSB0aGUgZGF0YSBmaXJzdCwgdGhlbiBmaW5kIGFuIGFwcHJvcHJpYXRlIHF1ZXN0aW9uLgoKSSdtIGdvaW5nIHRvIHF1aWNrbHkgcnVuIHRocm91Z2ggbXkgaXRlcmF0aW9uIGN5Y2xlIGZvciBmaW5kaW5nIGEgZGF0YSBzZXQuCjEuIFNldCBhIGdvYWwgZm9yIHRoZSB0YXNrIGFoZWFkCiogRGVmaW5lIGV4cGVjdGF0aW9ucyBvciBjcml0ZXJpYSBmb3Igc3VjY2VzcwpUaGUgZ29hbCBpcyB0byBmaW5kIGEgZGF0YSBzZXQgdGhhdCBmcm9tIHNvbWUgcHJpdmF0ZSBzZWN0b3IgY29tcGFueSB0aGF0IHdpbGwKbGVuZCBpdHNlbGYgd2VsbCB0byBxdWVzdGlvbnMgYWJvdXQgdmFyaW91cyBwZXJmb3JtYW5jZSBmYWN0b3JzCgpTbyBJIGZvdW5kIHNvbWUgS2lja3N0YXJ0ZXIgZGF0YS4gVGhlcmUgYXJlIDQwIHNvbWV0aGluZyBmaWxlcywgMjAgbWIgZWFjaC4gTGV0J3MgCnN0YXJ0IHdpdGggdGhlIGZpcnN0IG9uZQpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Ka2lja3N0YXJ0ZXIgPC0gcmVhZF9jc3YoIktpY2tzdGFydGVyXzIwMTctMDgtMTVUMjJfMjBfNTFfOTU4Wi9LaWNrc3RhcnRlci5jc3YiKQpgYGAKCgpTbyBJIG5lZWQgdG8gaW5zcGVjdCB0aGlzIGRhdGFzZXQgYSBsaXR0bGUgYml0CkZpcnN0IEkgd2FudCB0byBrbm93IHRoZSBkYXRlIHJhbmdlIG9mIHRoaXMgZG9jdW1lbnQKVGhhdCByZXF1aXJlcyB0aGF0IEkgY29udmVydCBhbGwgb2YgdGhlIGRhdGVzIGludG8gYSB1c2FibGUgZm9ybWF0OgoKYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmtpY2tzdGFydGVyJGNyZWF0ZWRfYXQgPC0gYXMuUE9TSVhjdChhcy5udW1lcmljKGtpY2tzdGFydGVyJGNyZWF0ZWRfYXQpLCBvcmlnaW4gPSAnMTk3MC0wMS0wMScsIHR6ID0gJ0dNVCcpCgpraWNrc3RhcnRlciRkZWFkbGluZSA8LSBhcy5QT1NJWGN0KGFzLm51bWVyaWMoa2lja3N0YXJ0ZXIkZGVhZGxpbmUpLCBvcmlnaW4gPSAnMTk3MC0wMS0wMScsIHR6ID0gJ0dNVCcpCgpraWNrc3RhcnRlciRzdGF0ZV9jaGFuZ2VkX2F0IDwtIGFzLlBPU0lYY3QoYXMubnVtZXJpYyhraWNrc3RhcnRlciRzdGF0ZV9jaGFuZ2VkX2F0KSwgb3JpZ2luID0gJzE5NzAtMDEtMDEnLCB0eiA9ICdHTVQnKQoKa2lja3N0YXJ0ZXIkbGF1bmNoZWRfYXQgPC0gYXMuUE9TSVhjdChhcy5udW1lcmljKGtpY2tzdGFydGVyJGxhdW5jaGVkX2F0KSwgb3JpZ2luID0gJzE5NzAtMDEtMDEnLCB0eiA9ICdHTVQnKQoKVmlldyhraWNrc3RhcnRlcikKYGBgCgpOZXh0IGxldHMgZXhwbG9yZSB0aGUgZGF0ZSByYW5nZS4gSSdsbCBhcmJpdHJhcmlseSBwaWNrIHRoZSBsYXVuY2ggZGF0ZXMgdG8gc3R1ZHkKYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmtpY2tzdGFydGVyICU+JQogICAgYXJyYW5nZShsYXVuY2hlZF9hdCkgJT4lCiAgICBzdW1tYXJpc2UobWF4KGxhdW5jaGVkX2F0KSwgbWluKGxhdW5jaGVkX2F0KSkKYGBgCgpJbnRlcmVzdGluZy4gVGhhdCBzZWVtcyB0byBnbyBhbGwgdGhlIHdheSB1bnRpbCBmcm9tIDIwMDkgdW50aWwgdGhlIGRhdGUgdGhleSB3ZXJlIHNjcmFwZWQuCgpJIGd1ZXNzIEknbGwgaGF2ZSB0byBleHBsb3JlIHNvbWUgb3RoZXIgZmlsZXMuIFBlcmhhcHMgdGhpcyBpcyBhIGNvbXBpbGF0aW9uIG9yIHNhbXBsZS4KCgpTbyBsZXQncyB3cml0ZSBhIGNvdXBsZSBmdW5jdGlvbnMgdG8gaW1wb3J0IGV2ZXJ5dGhpbmcsIHRoZW4gd2UnbGwgam9pbiB0aGUgZGF0YXNldHMgYW5kCmNvbnZlcnQgdGhlIGRhdGVzCgpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaW1wb3J0X2tpY2tzdGFydGVyIDwtIGZ1bmN0aW9uKCkgewogICAgZm9yKGkgaW4gMTo0MSl7CiAgICAgICAgZmlsZW5hbWUgPC0gc3ByaW50ZigiS2lja3N0YXJ0ZXIlMDNkIiwgaSkKICAgICAgICB2YXJfbmFtZSA8LSBzcHJpbnRmKCJraWNrc3RhcnRlciUwM2QiLCBpKQogICAgICAgIGRpcmVjdG9yeSA8LSAiS2lja3N0YXJ0ZXJfMjAxNy0wOC0xNVQyMl8yMF81MV85NThaIgogICAgICAgIHBhdGggPC0gcGFzdGUoZGlyZWN0b3J5LCBmaWxlbmFtZSwgc2VwID0gIi8iKQogICAgICAgIGZ1bGxfcGF0aCA8LSBwYXN0ZShwYXRoLCAiY3N2Iiwgc2VwID0gIi4iKQogICAgICAgIHZhcl9uYW1lIDwtIHJlYWRfY3N2KGZ1bGxfcGF0aCkKCiAgICB9Cn0KCmBgYApgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaW1wb3J0X2tpY2tzdGFydGVyKCkKYGBgCmBgYHtyLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppIDwtIDIKICAgICAgICBmaWxlbmFtZSA8LSBzcHJpbnRmKCJLaWNrc3RhcnRlciUwM2QiLCBpKQogICAgICAgIHZhcl9uYW1lIDwtIHNwcmludGYoImtpY2tzdGFydGVyJTAzZCIsIGkpCiAgICAgICAgZGlyZWN0b3J5IDwtICJLaWNrc3RhcnRlcl8yMDE3LTA4LTE1VDIyXzIwXzUxXzk1OFoiCiAgICAgICAgcGF0aCA8LSBwYXN0ZShkaXJlY3RvcnksIGZpbGVuYW1lLCBzZXAgPSAiLyIpCiAgICAgICAgZnVsbF9wYXRoIDwtIHBhc3RlKHBhdGgsICJjc3YiLCBzZXAgPSAiLiIpCiAgICAgICAgc3ByaW50Zigia2lja3N0YXJ0ZXIlMDNkIiwgaSkgPC0gcmVhZF9jc3YoZnVsbF9wYXRoKQoKZmlsZW5hbWUKdmFyX25hbWUKZGlyZWN0b3J5CnBhdGgKZnVsbF9wYXRoCmBgYApUaGlzIGlzIHRoZSBvbmUgdGhhdCB3b3JrZWQ6CmBgYHtyLCBpbmNsdWRlPUZBTFNFfQpmaWxlcyA8LSBsaXN0LmZpbGVzKHBhdHRlcm4gPSAiKi5jc3YiKQpraWNrc3RhcnRlciA8LSBmaWxlcyAlPiUKICAgIG1hcChyZWFkX2NzdikgJT4lCiAgICBiaW5kX3Jvd3MoKSAKVmlldyhraWNrc3RhcnRlcikKYGBgCgpCb29tISBHb3QgaXQgaW1wb3J0ZWQgYW5kIGNvbWJpbmVkISBUaGF0IHBpcGUgdGhpbmcgaXMga2luZGEgY29vbC4KYGBge3J9CmhlYWQoa2lja3N0YXJ0ZXIpCmBgYAoKYGBge3J9Cm5fZGlzdGluY3Qoa2lja3N0YXJ0ZXIpCmBgYAoKYGBge3J9CmRpbShraWNrc3RhcnRlcikKYGBgCgpgYGB7cn0Kc3RyKGtpY2tzdGFydGVyKQpgYGAKCmBgYHtyfQpjb2xuYW1lcyhraWNrc3RhcnRlcikKYGBgCmBgYHtyfQpuYW1lcyhraWNrc3RhcnRlcikKCmBgYAoKCmBgYHtyfQpzdW1tYXJ5KGtpY2tzdGFydGVyKQpgYGAKCmBgYHtyfQpzdW1tYXJ5KGtpY2tzdGFydGVyWzE0OjE3XSkKYGBgCmBgYHtyfQpmb3JtYXQob2JqZWN0LnNpemUoa2lja3N0YXJ0ZXIpLCB1bml0cyA9ICJNYiIpCm9iamVjdC5zaXplKGtpY2tzdGFydGVyKQpgYGAKCgpTTyB0aGF0IGxlYXZlcyB1cyB3aXRoIGEgc2hvcnQgbGlzdCBvZiB1c2VmdWwgdGFza3MgZm9yIGluc3BlY3RpbmcgdGhlIGRhdGFzZXQ6CmhlYWQoKQpzdHIoKQpzdW1tYXJ5KCkKZGltKCkKbl9kaXN0aW5jdCgpCmNvbG5hbWVzKCkgb3IgbmFtZXMoKQpvYmplY3Quc2l6ZSgpICMgd2l0aCBmb3JtYXQoKSBhbmQgdW5pdHMgYXJnCgpDb252ZXJ0IHN0YXRlIHRvIGEgZmFjdG9yCgpgYGB7cn0KaXMuZmFjdG9yKGtpY2tzdGFydGVyJHN0YXRlKQpraWNrc3RhcnRlciRzdGF0ZSA8LSBhcy5mYWN0b3Ioa2lja3N0YXJ0ZXIkc3RhdGUpCmlzLmZhY3RvcihraWNrc3RhcnRlciRzdGF0ZSkKCmBgYAoKQ29udmVydCBkYXRlcwoKYGBge3J9CmtpY2tzdGFydGVyJGNyZWF0ZWRfYXQgPC0gYXMuUE9TSVhjdChhcy5udW1lcmljKGtpY2tzdGFydGVyJGNyZWF0ZWRfYXQpLCBvcmlnaW4gPSAnMTk3MC0wMS0wMScsIHR6ID0gJ0dNVCcpCmtpY2tzdGFydGVyJGRlYWRsaW5lIDwtIGFzLlBPU0lYY3QoYXMubnVtZXJpYyhraWNrc3RhcnRlciRkZWFkbGluZSksIG9yaWdpbiA9ICcxOTcwLTAxLTAxJywgdHogPSAnR01UJykKa2lja3N0YXJ0ZXIkc3RhdGVfY2hhbmdlZF9hdCA8LSBhcy5QT1NJWGN0KGFzLm51bWVyaWMoa2lja3N0YXJ0ZXIkc3RhdGVfY2hhbmdlZF9hdCksIG9yaWdpbiA9ICcxOTcwLTAxLTAxJywgdHogPSAnR01UJykKa2lja3N0YXJ0ZXIkbGF1bmNoZWRfYXQgPC0gYXMuUE9TSVhjdChhcy5udW1lcmljKGtpY2tzdGFydGVyJGxhdW5jaGVkX2F0KSwgb3JpZ2luID0gJzE5NzAtMDEtMDEnLCB0eiA9ICdHTVQnKQpoZWFkKGtpY2tzdGFydGVyKQoKYGBgCgpQYXJzZSBEYXRlcwpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KcGFyc2VfZGF0ZV90aW1lKGtpY2tzdGFydGVyJGRlYWRsaW5lKQpgYGAKTWF5YmUgSSBkb24ndCBuZWVkIHRvIHBhcnNlPyBTZWVtcyB0b28gZWFzeS4uLgoKYGBge3J9CmtpY2tzdGFydGVyICU+JQogICAgYXJyYW5nZShsYXVuY2hlZF9hdCkgJT4lCiAgICBzdW1tYXJpc2UobWluKGxhdW5jaGVkX2F0KSwgbWF4KGxhdW5jaGVkX2F0KSkKa2lja3N0YXJ0ZXIgJT4lCiAgICBhcnJhbmdlKGNyZWF0ZWRfYXQpICU+JQogICAgc3VtbWFyaXNlKG1pbihjcmVhdGVkX2F0KSwgbWF4KGNyZWF0ZWRfYXQpKQpgYGAKYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmtpY2tzdGFydGVyICU+JQogICAgbXV0YXRlKGNyZWF0ZWRfdG9fbGF1bmNoZWQgPSBsYXVuY2hlZF9hdCAtIGNyZWF0ZWRfYXQsCiAgICAgICAgICAgY3JlYXRlZF90b19sYXVuY2hlZF9kYXlzID0gY3JlYXRlZF90b19sYXVuY2hlZCAvIDYwIC8gMjQpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmdncGxvdChkYXRhID0ga2lja3N0YXJ0ZXIsIGFlcyh4ID0gY3JlYXRlZF9hdCkpICsgCiAgICBnZW9tX2hpc3RvZ3JhbSgpCmdncGxvdChkYXRhID0ga2lja3N0YXJ0ZXIsIGFlcyh4ID0gbGF1bmNoZWRfYXQpKSArIAogICAgZ2VvbV9oaXN0b2dyYW0oKQpnZ3Bsb3QoZGF0YSA9IGtpY2tzdGFydGVyLCBhZXMoeCA9IGNyZWF0ZWRfdG9fbGF1bmNoZWQpKSArIAogICAgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKCk5vcm1hbCB0aW1lIGJldHdlZW4gY3JlYXRpb24gYW5kIGxhdW5jaD8KYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmtpY2tzdGFydGVyICU+JQogICAgbXV0YXRlKGNyZWF0ZWRfdG9fbGF1bmNoZWQgPSBhcy5udW1lcmljKHNlY29uZHNfdG9fcGVyaW9kKGFzLmludGVydmFsKGNyZWF0ZWRfYXQsIGxhdW5jaGVkX2F0KSkpKSAlPiUKICAgIGdncGxvdChhZXMoY3JlYXRlZF90b19sYXVuY2hlZCkpICsgCiAgICBnZW9tX2hpc3RvZ3JhbSgpICsKICAgIHhsaW0oYygwLCAxMDAwMCkpCiAgICAKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KZ2dwbG90KGFlcyhhcy5udW1lcmljKGNyZWF0ZWRfdG9fbGF1bmNoZWQpKSkgKyAKICAgIGdlb21faGlzdG9ncmFtKGJpbnMgPSAyMCkgCgpgYGAKCkJhY2sgdG8gbXkgZmlyc3QgaXRlcmF0aW9uIGN5Y2xlOiBmaW5kaW5nIGEgZGF0YXNldC4KCkZyb20gZWFybGllcjoKSSdtIGdvaW5nIHRvIHF1aWNrbHkgcnVuIHRocm91Z2ggbXkgaXRlcmF0aW9uIGN5Y2xlIGZvciBmaW5kaW5nIGEgZGF0YSBzZXQuCjEuIFNldCBhIGdvYWwgZm9yIHRoZSB0YXNrIGFoZWFkCiogRGVmaW5lIGV4cGVjdGF0aW9ucyBvciBjcml0ZXJpYSBmb3Igc3VjY2VzcwpUaGUgZ29hbCBpcyB0byBmaW5kIGEgZGF0YSBzZXQgdGhhdCBmcm9tIHNvbWUgcHJpdmF0ZSBzZWN0b3IgY29tcGFueSB0aGF0IHdpbGwKbGVuZCBpdHNlbGYgd2VsbCB0byBxdWVzdGlvbnMgYWJvdXQgdmFyaW91cyBwZXJmb3JtYW5jZSBmYWN0b3JzCgpBbmQgYSByZW1pbmRlciBvZiBteSBpdGVyYXRpb24gcHJvY2VzczoKTXkgZ29hbCBiYXNlZCBpdGVyYXRpb24gY3ljbGUgaXMgY3VycmVudGx5IGFzIGZvbGxvd3M6CjEuIFNldCBhIGdvYWwgZm9yIHRoZSB0YXNrIGFoZWFkCiogRGVmaW5lIGV4cGVjdGF0aW9ucyBvciBjcml0ZXJpYSBmb3Igc3VjY2VzcwoyLiBBdHRlbXB0IHRvIGNvbXBsZXRlIHRoZSBnb2FsIG9yIHBlcmZvcm0gdGhlIHRhc2sKMy4gQ29tcGFyZSB5b3VyIHJlc3VsdHMgdG8geW91ciBleHBlY3RhdGlvbnMgb3IgeW91ciBjcml0ZXJpYSBmb3Igc3VjY2Vzcwo0LiAoT3B0aW9uYWwpIFVzZSBqdWRnbWVudCBhbmQgZXhwZXJpZW5jZSB0byBkZWNpZGUgd2hldGhlciB5b3UgdGhpbmsgdGhlIGV4cGVjdGF0aW9ucyBzaG91bGQgYmUgYWx0ZXJlZCwgb3IgdGhlIHRhc2sgc2hvdWxkIGJlIHJlcGVhdGVkIHVuZGVyIGRpZmZlcmVudCBwYXJhbWV0ZXJzCjUuIE1ha2UgYWRqdXN0bWVudHMKCjIuIEF0dGVtcHQgdG8gY29tcGxldGUgdGhlIGdvYWwgb3IgcGVyZm9ybSB0aGUgdGFzawpEb25lCgozLiBDb21wYXJlIHlvdXIgcmVzdWx0cyB0byB5b3VyIGV4cGVjdGF0aW9ucyBvciB5b3VyIGNyaXRlcmlhIGZvciBzdWNjZXNzCktpY2tzdGFydGVyIGRhdGEgYWJvdXQgcG90ZW50aWFsIHN0YXJ0dXBzIHdhcyBkZWZpbml0ZWx5IG5vdCB3aGF0IEkgaGFkIGluIG1pbmQgKApJIHdhcyB0aGlua2luZyBtb3JlIGFsb25nIHRoZSBsaW5lcyBvZiBhIHNpbmdsZSBwcml2YXRlIHNlY3RvciBjb21wYW55KQoKNC4gKE9wdGlvbmFsKSBVc2UganVkZ21lbnQgYW5kIGV4cGVyaWVuY2UgdG8gZGVjaWRlIHdoZXRoZXIgeW91IHRoaW5rIHRoZSBleHBlY3RhdGlvbnMgc2hvdWxkIGJlIGFsdGVyZWQsIG9yIHRoZSB0YXNrIHNob3VsZCBiZSByZXBlYXRlZCB1bmRlciBkaWZmZXJlbnQgcGFyYW1ldGVycy4KTXkgaW50ZXJwcmV0YXRpb24gaXMgdGhhdCB0aGUgZXhwZWN0YXRpb25zIHNob3VsZCBiZSBhbHRlcmVkIChhbmQgd2Ugc2hvdWxkIHN0aWNrCndpdGggdGhlIEtpY2tzdGFydGVyIGRhdGEpCgpBbmQgbm93IGxldCdzIHdvcmsgb24gdGhlIHF1ZXN0aW9uCjEuIFNldCBhIGdvYWwgZm9yIHRoZSB0YXNrIGFoZWFkCiogRGVmaW5lIGV4cGVjdGF0aW9ucyBvciBjcml0ZXJpYSBmb3Igc3VjY2VzcwpUaGUgZ29hbCBpcyB0byBoYXZlIGEgcXVlc3Rpb24gdGhhdCB3aWxsIG1lZXQgc2V2ZXJhbCBjcml0ZXJpYToKICAgIDEuIFRoZSBhbnN3ZXIgbWF5IHByb3ZpZGUgaW5zaWdodCBpbnRvIGZhY3RvcnMgdGhhdCBsZWFkIHRvIHN1Y2Nlc3NmdWwgZnVuZGluZwogICAgb24gS2lja3N0YXJ0ZXIuCiAgICAyLiBDYW4gYmUgYW5zd2VyZWQgd2l0aCB0aGUgY3VycmVudCBkYXRhc2V0LgogICAgMy4gUHJvdmlkZXMgdGhlIG9wcG9ydHVuaXR5IHRvIGFwcGx5IHRoZSBQcm9jZXNzIG9mIERhdGEgU2NpZW5jZQogICAgNC4gQWxsb3dzIGZvciBleHBsb3JhdGlvbiBvZiB0aGUgc2ltaWxhcml0aWVzIGFuZCBkaWZmZXJlbmNlcyBiZXR3ZWVuIEluZmVyZW50aWFsCiAgICBhbmQgUHJlZGljdGl2ZSBxdWVzdGlvbnMuIFRoZSBxdWVzdGlvbiBzaG91bGQgZmFsbCBpbnRvIG9uZSBvZiB0aGUgY2F0ZWdvcmllcywgYnV0IAogICAgY291bGQgYmUgdmFyaWVkIHNsaWdodGx5IHRvIGZhbGwgaW50byB0aGUgb3RoZXIgZm9yIGxlYXJuaW5nIHB1cnBvc2VzLgogICAgNS4gQmUgc3VmZmljaWVudGx5IHNoYXJwIHRvIHByb3ZpZGUgdXNlZnVsIGluc2lnaHQuCgoyLiBBdHRlbXB0IHRvIGNvbXBsZXRlIHRoZSBnb2FsIG9yIHBlcmZvcm0gdGhlIHRhc2sKRmlyc3QgcGFzczogYmUgdmVyeSBnZW5lcmFsLgpBdHRlbXB0OiBXaGF0IGlzIHRoZSBmYWN0b3IgdGhhdCBiZXN0IHByZWRpY3RzIHN1Y2Nlc3NmdWwgZnVuZGluZyBvbiBLaWNrc3RhcnRlcj8KCjMuIENvbXBhcmUgeW91ciByZXN1bHRzIHRvIHlvdXIgZXhwZWN0YXRpb25zIG9yIHlvdXIgY3JpdGVyaWEgZm9yIHN1Y2Nlc3MKV2UnbGwgZG8gdGhpcyBvbmUgYnkgb25lLgoxLiBUaGUgYW5zd2VyIG1heSBwcm92aWRlIGluc2lnaHQgaW50byBmYWN0b3JzIHRoYXQgbGVhZCB0byBzdWNjZXNzZnVsIGZ1bmRpbmcKICAgIG9uIEtpY2tzdGFydGVyLgotSSB0aGluayBJJ3ZlIGFjY29tcGxpc2hlZCB0aGlzIG9uZS4gSWYgd2UgYW5zd2VyIHRoZSBxdWVzdGlvbiwgd2Ugd291bGQga25vdyBhYm91dCB0aGUgZmFjdG9ycyB0aGF0IGNvbnRyaWJ1dGUgdG8gc3VjY2Vzcy4gSXQgZmVlbHMgaXRzIHVzZWZ1bG5lc3MgaXMgbGltaXRlZCBieSBvbmx5IGxvb2tpbmcKZm9yIHRoZSBzaW5nbGUgYmVzdCB2YXJpYWJsZS4gUGVyaGFwcyB3ZSBjb3VsZCBjaGFuZ2UgaXQgdG8gImZhY3RvciBvciBjb21iaW5hdGlvbiBvZgpmYWN0b3JzIi4KCk5ldyBxdWVzdGlvbjogV2hhdCBmYWN0b3Igb3IgY29tYmluYXRpb24gb2YgZmFjdG9ycyBiZXN0IHByZWRpY3Qgc3VjY2Vzc2Z1bCBmdW5kaW5nIG9uCktpY2tzdGFydGVyPwoKTm93IHdlJ2xsIGNvbXBhcmUgaXQgdG8gY3JpdGVyaWEgIzIuCiAgICAyLiBDYW4gYmUgYW5zd2VyZWQgd2l0aCB0aGUgY3VycmVudCBkYXRhc2V0LgotVGhpcyBvbmUgcmVxdWlyZXMgYSBsaXR0bGUgcmVzZWFyY2ggYW5kIHRob3VnaHQuCmBgYHtyfQpuYW1lcyhraWNrc3RhcnRlcikKYGBgClNvIHdoYXQgdmFyaWFibGVzIGhhdmUgYW55IGNoYW5jZSBvZiBiZWluZyB1c2VmdWwgaGVyZT8KaWQtbm8KcGhvdG8tbm8KbmFtZS1wb3NzaWJseQpibHVyYi1wb3NzaWJseQpnb2FsLXBvc3NpYmx5CnBsZWRnZWQtcG9zc2libHkKc3RhdGUtcG9zc2libHkKc2x1Zy1wb3NzaWJseQpkaXNhYmxlX2NvbW11bmljYXRpb24tcG9zc2libHkKY291bnRyeS1wb3NzaWJseQpjdXJyZW5jeS1wb3NzaWJseQpjdXJyZW5jeV9zeW1ib2wtbm8KY3VycmVuY3lfdHJhaWxpbmdfY29kZS1ubwpkZWFkbGluZS1wb3NzaWJseQpzdGF0ZV9jaGFuZ2VkX2F0LXBvc3NpYmx5CmNyZWF0ZWRfYXQtcG9zc2libHkKbGF1bmNoZWRfYXQtLXBvc3NpYmx5CnN0YWZmX3BpY2stcG9zc2libHkKaXNfc3RhcnJhYmxlLXBvc3NpYmx5CmJhY2tlcnNfY291bnQtcG9zc2libHkKc3RhdGljX3VzZF9yYXRlLW5vCnVzZC1wbGVkZ2VkLXBvc3NpYmx5CmNyZWF0b3ItcG9zc2libHkKbG9jYXRpb24tcG9zc2libHkKY2F0ZWdvcnktcG9zc2libHkKcHJvZmlsZS1wb3NzaWJseQpzcG90bGlnaHQtcG9zc2libHkKdXJscy1ubwpzb3VyY2UtdXJsCmZyaWVuZHMtcG9zc2libHkKaXNfc3RhcnJlZC1wb3NzaWJseQppc19iYWNraW5nLXBvc3NpYmx5CnBlcm1pc3Npb25zLXBvc3NpYmx5CgpTbyBhIGxvdCBvZiB0aG9zZSB3aWxsIHJlcXVpcmUgbW9yZSBpbmZvIGFib3V0IHdoYXQgZWFjaCBvZiB0aG9zZSB2YXJpYWJsZXMgYWN0dWFsbHkKY29udGFpbi4gV2UgY2FuIGdvIGxvb2ssIGJ1dCByaWdodCBub3cgd2UganVzdCBuZWVkIGEgcm91Z2ggaWRlYSBhYm91dCB3aGV0aGVyIG9yIG5vdCB3ZQpoYXZlIGEgY2hhbmNlIG9mIGFuc3dlcmluZyB0aGUgcXVlc3Rpb24uIFdlIGNhbiBleHBsb3JlIHdoYXQgaW5mb3JtYXRpb24gZWFjaCBvZiB0aG9zZSAKdmFyaWFibGVzIGNvbnRhaW5zIGluIHRoZSBuZXh0IHN0YWdlIChFREEpLgoKQW5kIG9uIHRvIGNyaXRlcmlhICMzOgozLiBQcm92aWRlcyB0aGUgb3Bwb3J0dW5pdHkgdG8gYXBwbHkgdGhlIFByb2Nlc3Mgb2YgRGF0YSBTY2llbmNlClNpbmNlIHdlIGhhdmUgbmVhcmx5IGNvbXBsZXRlZCBzdGFnZSAxLCBsZXRzIHdhbGsgdGhyb3VnaCB0aGUgbmV4dCA0IHN0YWdlcywgc2ltcGx5IGRlY2lkaW5nCndoZXRoZXIgd2UgYXJlIGxpa2VseSBvciBub3QgdG8gYmUgYWJsZSB0byB1c2UgdGhpcyBxdWVzdGlvbiBhdCBlYWNoIHN0YWdlClN0YWdlIDI6IEVEQSAtIHllcwpTdGFnZSAzOiBCdWlsZCBhIG1vZGVsIC0geWVzClN0YWdlIDQ6IEludGVycHJldCB0aGUgcmVzdWx0cyAtIHllcwpTdGFnZSA1OiBDb21tdW5pY2F0ZSAtIHllcwpPdmVyYWxsOiB5ZXMKCkNyaXRlcmlhIDQ6CjQuIEFsbG93cyBmb3IgZXhwbG9yYXRpb24gb2YgdGhlIHNpbWlsYXJpdGllcyBhbmQgZGlmZmVyZW5jZXMgYmV0d2VlbiBJbmZlcmVudGlhbAogICAgYW5kIFByZWRpY3RpdmUgcXVlc3Rpb25zLiBUaGUgcXVlc3Rpb24gc2hvdWxkIGZhbGwgaW50byBvbmUgb2YgdGhlIGNhdGVnb3JpZXMsIGJ1dCAKICAgIGNvdWxkIGJlIHZhcmllZCBzbGlnaHRseSB0byBmYWxsIGludG8gdGhlIG90aGVyIGZvciBsZWFybmluZyBwdXJwb3Nlcy4KLVRoaXMgb25lIHJlcXVpcmVzIGEgZmV3IGRlZmluaXRpb25zOgpBbiAqKmluZmVyZW50aWFsIGRhdGEgYW5hbHlzaXMqKiBxdWFudGlmaWVzCndoZXRoZXIgYW4gb2JzZXJ2ZWQgcGF0dGVybiB3aWxsIGxpa2VseSBob2xkCmJleW9uZCB0aGUgZGF0YSBzZXQgaW4gaGFuZC4gCgpHb2luZyBiZXlvbmQgYW4gaW5mZXJlbnRpYWwgZGF0YSBhbmFseXNpcywKd2hpY2ggcXVhbnRpZmllcyB0aGUgcmVsYXRpb25zaGlwcyBhdCBwb3B1bGF0aW9uCnNjYWxlLCBhICoqcHJlZGljdGl2ZSBkYXRhIGFuYWx5c2lzKiogdXNlcwphIHN1YnNldCBvZiBtZWFzdXJlbWVudHMgKHRoZSBmZWF0dXJlcykKdG8gcHJlZGljdCBhbm90aGVyIG1lYXN1cmVtZW50ICh0aGUgb3V0Y29tZSkKb24gYSBzaW5nbGUgcGVyc29uIG9yIHVuaXQuIAoKU2hpdCAtIEkganVzdCByZWFsaXplZCBzb21ldGhpbmcuIEFzIGl0cyBwaHJhc2VkLCBJIHdvdWxkIGJlIHRyeWluZyB0byBwZXJmb3JtIGNsYXNzaWZpY2F0aW9uLCByYXRoZXIgdGhhbiByZWdyZXNzaW9uIHdpdGggYSBjb250aW51b3VzIG91dGNvbWUuIEhtbW1tLgpJcyB0aGVyZSBhIHZhcmlhYmxlIEkgY291bGQgdXNlIGFzIGFuIG91dGNvbWUgdGhhdCBpcyBjb250aW51b3VzPyAKcGxlZGdlZCwgYmFja2Vyc19jb3VudCwgb3IgKG11dGF0ZWQpIHBsZWRnZWQgYXMgYSBwZXJjZW50YWdlIG9mIGdvYWwuCkkgdGxpa2UgdGhlIHBsZWRnZWQgYXMgYSBwZXJjZW50YWdlIG9mIGdvYWwgYmVjYXVzZSBpdCBnaXZlcyBkZWdyZWVzIG9mIHN1Y2Nlc3MsIGluc3RlYWQgb2YganVzdCBiaW5hcnkuIE90aGVyd2lzZSwgYmFyZWx5IGZhaWxlZCBhbmQgcmVhbGx5IGZhaWxlZCB3b3VsZCBiZSB0cmVhdGVkIHRoZSBzYW1lLiBTaW1pbGFybHksIGJhcmVseSBmYWlsZWQgYW5kIGJhcmVseSBzdWNjZWVkZWQgd291bGQgYmUgdHJlYXRlZCBhcyBjb21wbGV0ZWx5IGRpZmZlcmVudC4KT2sgSSBsaWtlIHRoYXQuIENyaXNpcyBhdmVydGVkLiBJIGNvdWxkIGFsc28gdXNlIHRoZSBiaW5hcnkgdmVyc2lvbiBhcyBhIG1lYW5zIG9mIGNvbXBhcmlzb24sIGFuZCBzaW1wbHkgdG8gc2hvdyBhbm90aGVyIHR5cGUgb2YgbW9kZWwuCgpTbyBiYWNrIHRvIGluZmVyZW50aWFsIHYgcHJlZGljdGl2ZSwgYXMgb3JpZ2luYWxseSBwaHJhc2VkLCBpdCBpcyBhIHByZWRpY3RpdmUgcXVlc3Rpb24uClRoaXMgaXMgbW9yZSB1c2VmdWwgdGhhbiBhdHRlbXB0aW5nIHRvIGRldGVybWluZSB3aGV0aGVyIG9yIG5vdCBpdCB3b3VsZCBob2xkIGF0IHRoZSBwb3B1bGF0aW9uIHNjYWxlLiBXZSBjYW4gc3RpY2sgd2l0aCBwcmVkaWN0aW9uLCBidXQgc2hvdyBob3cgdG8gdXNlIGluZmVyZW50aWFsIHN0YXRpc3RpY3Mgd2hlbiBuZWNlc3NhcnkuCgpBbmQgZmluYWxseSwgY3JpdGVyaWEgIzU6CiAgICA1LiBCZSBzdWZmaWNpZW50bHkgc2hhcnAgdG8gcHJvdmlkZSB1c2VmdWwgaW5zaWdodC4KQXMgaXQgc3RhbmRzLCBpdCBpcyBub3Qgc2hhcnAuIEhvd2V2ZXIsIHdlIGNhbiBzaGFycGVuIGFzIG5lY2Vzc2FyeS4gV2UgY2FuIHB1dCB0b2dldGhlciBzaGFycGVyIHF1ZXN0aW9ucyBpbiBvcmRlciB0byB0ZXN0IG91ciBtb2RlbHMgKGh5cG90aGVzZXMpLgotSSBtaWdodCB0YWtlIHRoaXMgb25lIG91dC4KCldlIGNvdWxkIGFsc28gY29tcGFyZSB0byBBb0RTIGNyaXRlcmlhOgpDaGFyYWN0ZXJpc3RpY3Mgb2YgYSBHb29kIFF1ZXN0aW9uOgoxLiBTaG91bGQgYmUgb2YgaW50ZXJlc3QgdG8geW91ciBhdWRpZW5jZQoyLiBTaG91bGQgbm90IGhhdmUgYWxyZWFkeSBiZWVuIGFuc3dlcmVkCjMuIFNob3VsZCBzdGVtIGZyb20gYSBwbGF1c2libGUgZnJhbWV3b3JrCjQuIFNob3VsZCBiZSBhbnN3ZXJhYmxlCjUuIFNwZWNpZmljaXR5CgpCdXQgdGhhdCBzb3VuZHMgYSBsaXR0bGUgYm9yaW5nLi4uCgpJIHRoaW5rIEkgaGF2ZSBzdWZmaWNpZW50bHkgbWV0IG15IGNyaXRlcmlhIGFmdGVyIHRoZSBvbmUgaXRlcmF0aW9uLiBBbG1vc3QgdG9vIGVhc3kuCgpJdCdzIHdvcnRoIGRpc2N1c3NpbmcgaG93IHRoaXMgcHJvY2VzcyBjb250aW51ZXMgdGhyb3VnaCAoYXQgbGVhc3QpIHRoZSBuZXh0IHR3byBzdGFnZXMuIFRoZSBwdXJwb3NlIG9mIEVEQSBpcyB0byBleHBsb3JlIHRoZSB2YXJpYWJsZXMsIGlkZW50aWZ5IHJlbGF0aW9uc2hpcHMsIGFuZCBnZW5lcmF0ZSBpZGVhcyB0byB0ZXN0IGZ1cnRoZXIuIFdlIHdpbGwgY29tZSB1cCB3aXRoIG1vcmUgc3BlY2lmaWMgcXVlc3Rpb25zIHRvIHRlc3QgbGF0ZXIuIFNwZWNpZmljaXR5IHdpbGwgaW5jcmVhc2UgdG8gdGhlIHBvaW50IG9mIGJlY29taW5nIGEgaHlwb3RoZXNpcyAob3IgcGFpciBvZiBoeXBvdGhlc2VzKS4KClNvIG9udG8gc29tZSBjbGVhbmluZyBhbmQgdGlkeWluZy4KCkxldCdzIGZpcnN0IGNvbXBhcmUgdG8gdGlkeSBwcmluY2lwbGVzOgoxLiBFYWNoIHZhcmlhYmxlIGZvcm1zIGEgY29sdW1uLiAKMi4gRWFjaCBvYnNlcnZhdGlvbiBmb3JtcyBhIHJvdy4gCjMuIEVhY2ggdHlwZSBvZiBvYnNlcnZhdGlvbmFsIHVuaXQgZm9ybXMgYSB0YWJsZQoKV2UncmUgYWN0dWFsbHkgcHJldHR5IHRpZHkgYWxyZWFkeS4gV2hlbiBJIGdvIGJhY2sgdGhyb3VnaCwgSSBzaG91bGQgZmluZCBzb21lIG1lc3N5IGRhdGFzZXRzIGFuZCBwZXJmb3JtIHNvbWUgYmFzaWMgdGlkeWluZy4KCk90aGVyIGNvbW1vbiBkYXRhIGNsZWFuaW5nIHRhc2tzOgpvdXRsaWVyIGNoZWNraW5nIApkYXRlIHBhcnNpbmcgCm1pc3NpbmcgdmFsdWUgaW1wdXRhdGlvbgoKSSB0aGluayBJIHRvb2sgY2FyZSBvZiB0aGUgZGF0ZSBwYXJzaW5nLCByaWdodD8gV2hlbiBJIGNvbnZlcnRlZCBmcm9tIHVuaXgsIHRoZXkgd2VyZSBhbHJlYWR5IHBhcnNlZC4gQnV0IGxldHMgZ2V0IGEgZGVmaW5pdGlvbi4KClNvIGxldCdzIHN0YXJ0IGNoZWNraW5nIGZvciBhbmQgcGxheWluZyB3aXRoIG1pc3NpbmcgZGF0YS4gQkxBQUFBSEhISApgYGB7cn0Ka2lja3N0YXJ0ZXJbIWNvbXBsZXRlLmNhc2VzKGtpY2tzdGFydGVyKSxdCmBgYAoKYGBge3J9CmtpY2tzdGFydGVyW2NvbXBsZXRlLmNhc2VzKGtpY2tzdGFydGVyKSxdCmBgYAoKYGBge3J9Cm9wdGlvbnMoc2NpcGVuID0gOTk5KQpjb2xNZWFucyhpcy5uYShraWNrc3RhcnRlcikpCmBgYApgYGB7cn0KaGVhZChraWNrc3RhcnRlclszMDozM10sIDEwMCkKCmBgYApgYGB7cn0KbnJvdyhraWNrc3RhcnRlcikgKiBtZWFuKGlzLm5hKGtpY2tzdGFydGVyJGxvY2F0aW9uKSkKCmBgYAoKCmBgYHtyfQpzdW0oaXMubmEoa2lja3N0YXJ0ZXIkbG9jYXRpb24pKQpgYGAKClNvIHdoYXQgb3RoZXIgdGFza3Mgc2hvdWxkIEkgaW50cm9kdWNlIGFzIGRhdGEgY2xlYW5pbmc/ClBhcnNlIGRhdGVzCk1hbmlwdWxhdGUgc3RyaW5ncz8KQ29udmVydCB0byBmYWN0b3JzPwpNdXRhdGU/CkNoZWNrIGZvciBvdXRsaWVycz8gT3Igd2FpdCB1bnRpbCBFREE/CmBgYHtyLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJvdXRsaWVycyIpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9Cm91dGxpZXJzOjpvdXRsaWVyKGtpY2tzdGFydGVyJHBsZWRnZWQpCgpgYGAKCmBgYHtyfQpraWNrc3RhcnRlciAlPiUKICAgIHN1bW1hcmlzZShtYXgocGxlZGdlZCkpCmBgYApgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Kb3V0bGllcnM6OnJtLm91dGxpZXIoa2lja3N0YXJ0ZXIkcGxlZGdlZCkgJT4lCiAgICBnZ3Bsb3Qoa2lja3N0YXJ0ZXIsIGFlcyhwbGVkZ2VkKSkgKyAKICAgIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCkKYGBgCgpUaGlzIHNob3VsZCBiZSBkb25lIHZpc3VhbGx5CmBgYHtyfQpnZ3Bsb3Qoa2lja3N0YXJ0ZXIsIGFlcyhzdGF0ZSwgcGxlZGdlZCkpICsgCiAgICBnZW9tX2JveHBsb3QoKQpgYGAKYGBge3J9CmtpY2tzdGFydGVyICU+JQogICAgZmlsdGVyKHBsZWRnZWQgPiA3NTAwMDAwKSAKYGBgCgpgYGB7cn0Ka2lja3N0YXJ0ZXIgJT4lCiAgICBhcnJhbmdlKGRlc2MocGxlZGdlZCkpCmBgYAoKYGBge3IgR3JvdXBlZCBTdW1tYXJ5fQpraWNrc3RhcnRlciAlPiUKICAgIGdyb3VwX2J5KHN0YXRlKSAlPiUKICAgIHN1bW1hcmlzZShuKCksIG1lYW4ocGxlZGdlZCkpCmBgYAoKV2Ugc2hvdWxkIHByb2JhYmx5IHJlbW92ZSBsaXZlIGVudHJpZXMgc2luY2UgdGhleSBhcmUgbm90IGNvbXBsZXRlLgoKU2luY2UgbGl2ZSB3b3VsZCBpbmRpY2F0ZSBhIGRlYWRsaW5lIG9mIGFmdGVyIDgvMTUvMTcsIGxldCdzIHNlZSBpZiB3ZSBjYW4gc2VlIGhvdyBtYW55IHRoZXJlIGFyZSwgYW5kIGNvbXBhcmUgdG8gdGhvc2Ugd2l0aCB0aGUgbGl2ZSBzdGF0ZS4KCmBgYHtyfQpraWNrc3RhcnRlciAlPiUKICAgIGZpbHRlcihkZWFkbGluZSA+PSB5bWQoIjIwMTctMDgtMTUiKSkgJT4lCiAgICAgICAgZ3JvdXBfYnkoc3RhdGUpICU+JQogICAgIHN1bW1hcmlzZShuKCksIG1lYW4ocGxlZGdlZCkpCgpgYGAKClNvIHNvbWUgbWF5IGhhdmUgYmVlbiBzdXNwZW5kZWQgb3IgY2FuY2VsbGVkLCBvciBhbHNvIHJlYWNoZWQgdGhlaXIgZ29hbCBiZWZvcmUgdGhlIGRhdGEgd2FzIHNjcmFwZWQuIEJ1dCB0aGUgdmFzdCBtYWpvcml0eSBhcmUgbGl2ZS4gV2UgY291bGQgY2hlY2sgdGhhdCB0aGUgb3RoZXIgd2F5IGFzIHdlbGwsIGp1c3QgdG8gYmUgc3VyZSB3ZSBrbm93IHdoYXQgd2UncmUgd29ya2luZyB3aXRoLgoKYGBge3J9CmtpY2tzdGFydGVyICU+JQogICAgZmlsdGVyKGRlYWRsaW5lIDw9IHltZCgiMjAxNy0wOC0xNSIpKSAlPiUKICAgICAgICBncm91cF9ieShzdGF0ZSkgJT4lCiAgICAgc3VtbWFyaXNlKG4oKSwgbWVhbihwbGVkZ2VkKSkKCmBgYAoKCkNvbmZpcm1lZCBteSBzdXNwaWNpb24gdGhhdCBsaXZlIHJlY29yZHMgYXJlIGp1c3Qgb25lcyB0aGF0IGhhdmVuJ3QgbWV0IHRoZWlyIGRlYWRsaW5lIGFzIG9mIHRoZSB0aW1lIHRoZXkgd2VyZSBzY3JhcGVkLiBXZSBzaG91bGQgcmVtb3ZlIHRoZW0uCgpgYGB7cn0KMTY5ODMyLTM1NzMKa2lja3N0YXJ0ZXIgPC0ga2lja3N0YXJ0ZXIgJT4lCiAgICBmaWx0ZXIoc3RhdGUgIT0gImxpdmUiKQpucm93KGtpY2tzdGFydGVyKQpgYGAKCklzIHRoZSBkYXRhIHRpZHk/CkhhZGxleSdzIERlZmluaXRpb24gb2YgVGlkeSBEYXRhOgoxLiBFYWNoIHZhcmlhYmxlIGZvcm1zIGEgY29sdW1uLiAKMi4gRWFjaCBvYnNlcnZhdGlvbiBmb3JtcyBhIHJvdy4gCjMuIEVhY2ggdHlwZSBvZiBvYnNlcnZhdGlvbmFsIHVuaXQgZm9ybXMgYSB0YWJsZQoKWWVzIHdlIGFyZSBwcmV0dHkgbXVjaCB0aWR5LiBXaGVuIGkgY29tZSBiYWNrIHRocm91Z2ggaGVyZSwgSSBuZWVkIHRvIGNvbWUgdXAgd2l0aCAocmFuZG9tbHkgY29uc3RydWN0KSBhbiB1bnRpZHkgZGF0YXNldCwgYW5kIHBlcmZvcm0gc29tZSBjb21tb24gb3BlcmF0aW9ucyBvbiBpdC4KCkEgbGl0dGxlIG1vcmUgY2xlYW5pbmcgSSBjb3VsZCBkbyBpcyByZW1vdmUgc29tZSB1bmVjY2VzYXJ5IGNvbHVtbnMgdG8gbWFrZSB0aGluZ3MgYSBsaXR0bGUgZWFzaWVyIHRvIHNlZSBhbmQgd29yayB3aXRoLiBMZXQncyByZXZpc2l0IGEgY291cGxlIHRoaW5ncy4KYGBge3J9CmhlYWQoa2lja3N0YXJ0ZXIpCmBgYApTb21lIHBvc3NpYmxlIGNvbHVtbnMgdG8gcmVtb3ZlOgpwaG90bwpmcmllbmRzCmlzX3N0YXJyZWQKaXNfYmFja2luZwpwZXJtaXNzaW9ucwoKQSBmZXcgbmVlZCB0byBiZSBtYWRlIHRvIGZhY3RvcnM6CmRpc2FibGVfY29tbXVuaWNhdGlvbgpjb3VudHJ5CmN1cnJlbmN5CmN1cnJlbmN5X3N5bWJvbApjdXJyZW5jeV90cmFpbGluZ19jb2RlCnN0YWZmX3BpY2sgCmlzX3N0YXJyYWJsZSAKc3BvdGxpZ2h0IAoKCgpMZXQncyBtYWtlIHRoZSBmYWN0b3JzIHJlYWwgcXVpY2tseQpgYGB7cn0Ka2lja3N0YXJ0ZXIkc3RhdGUgPC0gYXMuZmFjdG9yKGtpY2tzdGFydGVyJHN0YXRlKQpraWNrc3RhcnRlciRkaXNhYmxlX2NvbW11bmljYXRpb24gPC0gYXMuZmFjdG9yKGtpY2tzdGFydGVyJGRpc2FibGVfY29tbXVuaWNhdGlvbikKa2lja3N0YXJ0ZXIkY291bnRyeSA8LSBhcy5mYWN0b3Ioa2lja3N0YXJ0ZXIkY291bnRyeSkKa2lja3N0YXJ0ZXIkY3VycmVuY3kgPC0gYXMuZmFjdG9yKGtpY2tzdGFydGVyJGN1cnJlbmN5KQpraWNrc3RhcnRlciRjdXJyZW5jeV9zeW1ib2wgPC0gYXMuZmFjdG9yKGtpY2tzdGFydGVyJGN1cnJlbmN5X3N5bWJvbCkKa2lja3N0YXJ0ZXIkY3VycmVuY3lfdHJhaWxpbmdfY29kZSA8LSBhcy5mYWN0b3Ioa2lja3N0YXJ0ZXIkY3VycmVuY3lfdHJhaWxpbmdfY29kZSkKa2lja3N0YXJ0ZXIkc3RhZmZfcGljayA8LSBhcy5mYWN0b3Ioa2lja3N0YXJ0ZXIkc3RhZmZfcGljaykKa2lja3N0YXJ0ZXIkaXNfc3RhcnJhYmxlIDwtIGFzLmZhY3RvcihraWNrc3RhcnRlciRpc19zdGFycmFibGUpCmtpY2tzdGFydGVyJHNwb3RsaWdodCA8LSBhcy5mYWN0b3Ioa2lja3N0YXJ0ZXIkc3BvdGxpZ2h0KQoKYGBgCgoKYGBge3J9Cm5hbWVzKGtpY2tzdGFydGVyKQpgYGAKCmBgYHtyfQpzdW1tYXJ5KGtpY2tzdGFydGVyKQpgYGAKU29tZSBwb3NzaWJsZSBjb2x1bW5zIHRvIHJlbW92ZToKcGhvdG8KZnJpZW5kcwppc19zdGFycmVkCmlzX2JhY2tpbmcKcGVybWlzc2lvbnMKCmBgYHtyfQpraWNrc3RhcnRlciA8LSBraWNrc3RhcnRlciAlPiUKICAgIHNlbGVjdCgtYyhwaG90bywgZnJpZW5kcywgaXNfc3RhcnJlZCwgaXNfYmFja2luZywgcGVybWlzc2lvbnMpKQpkaW0oa2lja3N0YXJ0ZXIpCmBgYApMZXQncyBhbHNvIHJlbW92ZSBwcm9maWxlCmBgYHtyfQpraWNrc3RhcnRlciA8LSBraWNrc3RhcnRlciAlPiUKICAgIHNlbGVjdCgtcHJvZmlsZSkKZGltKGtpY2tzdGFydGVyKQpoZWFkKGtpY2tzdGFydGVyKQpgYGAKaHR0cHM6Ly93d3cua2lja3N0YXJ0ZXIuY29tL2Rpc2NvdmVyL2NhdGVnb3JpZXMvYXJ0L2RpZ2l0YWwlMjBhcnQ/cmVmPWNhdGVnb3J5X21vZGFsJnNvcnQ9bWFnaWMKeyJ3ZWIiOnsicHJvamVjdCI6Imh0dHBzOi8vd3d3LmtpY2tzdGFydGVyLmNvbS9wcm9qZWN0cy9pdGhhcXVhbGFicy8xMDAtZmFudGFzeS1wb3J0cmFpdHMtZm9yLW9yaWEtdHJhaWwtdGhlLWdhbWU/cmVmPWNhdGVnb3J5X25ld2VzdCIsInJld2FyZHMiOiJodHRwczovL3d3dy5raWNrc3RhcnRlci5jb20vcHJvamVjdHMvaXRoYXF1YWxhYnMvMTAwLWZhbnRhc3ktcG9ydHJhaXRzLWZvci1vcmlhLXRyYWlsLXRoZS1nYW1lL3Jld2FyZHMifX0JCgpSZW1vdmUgdXJscwpgYGB7cn0Ka2lja3N0YXJ0ZXIgPC0ga2lja3N0YXJ0ZXIgJT4lCiAgICBzZWxlY3QoLXVybHMpCmRpbShraWNrc3RhcnRlcikKaGVhZChraWNrc3RhcnRlcikKYGBgCgpBbmQgYSBmZXcgdGhhdCBjb3VsZCB1c2Ugc29tZSBzdHJpbmcgbWFuaXB1bGF0aW9uOgpjcmVhdG9yCmxvY2F0aW9uCmNhdGVnb3J5CnByb2ZpbGUKCmBgYHtyfQpraWNrc3RhcnRlciAlPiUKICAgIHNlbGVjdChjYXRlZ29yeSkKYGBgCnsidXJscyI6eyJ3ZWIiOnsiZGlzY292ZXIiOiJodHRwOi8vd3d3LmtpY2tzdGFydGVyLmNvbS9kaXNjb3Zlci9jYXRlZ29yaWVzL2FydC9kaWdpdGFsJTIwYXJ0In19LCJjb2xvciI6MTY3NjAyMzUsInBhcmVudF9pZCI6MSwibmFtZSI6IkRpZ2l0YWwgQXJ0IiwiaWQiOjIxLCJwb3NpdGlvbiI6Mywic2x1ZyI6ImFydC9kaWdpdGFsIGFydCJ9Cgp7InVybHMiOnsid2ViIjp7ImRpc2NvdmVyIjoiaHR0cDovL3d3dy5raWNrc3RhcnRlci5jb20vZGlzY292ZXIvY2F0ZWdvcmllcy9hcnQvaWxsdXN0cmF0aW9uIn19LCJjb2xvciI6MTY3NjAyMzUsInBhcmVudF9pZCI6MSwibmFtZSI6IklsbHVzdHJhdGlvbiIsImlkIjoyMiwicG9zaXRpb24iOjQsInNsdWciOiJhcnQvaWxsdXN0cmF0aW9uIn0KYGBge3J9Cmxlbmd0aChsZXZlbHMoYXMuZmFjdG9yKGtpY2tzdGFydGVyJGNhdGVnb3J5KSkpCmBgYApMZXQncyBleHBlcmltZW50CgpgYGB7ciwgZXZhbCA9IEZBTFNFLCBpbmNsdWRlPUZBTFNFfQpzdHJpbmcgPC0gImFhYWFheGJiYmJieWNjY2MiCnggPC0gc3RyX2xvY2F0ZShzdHJpbmcsICJ4IikKeSA8LSBzdHJfbG9jYXRlKHN0cmluZywgInkiKQpkYXRhLmNsYXNzKHgpCmRhdGEuY2xhc3MoeFsxLDFdKQpzdHJfc3ViKHN0cmluZywgKHhbMSwxXSsxKSwgKHlbMSwxXS0xKSkKYGBgCmBgYHtyfQpleHRyYWN0X2NhdGVnb3J5IDwtIGZ1bmN0aW9uKHN0cmluZykgewogICAgb3V0cHV0IDwtIHZlY3RvcigiY2hhcmFjdGVyIiwgbGVuZ3RoKHN0cmluZykpCiAgICBzdGFydCA8LSAnIm5hbWUiOiInCiAgICBlbmQgPC0gJyJpZCInCiAgICBmb3IgKGkgaW4gc2VxX2Fsb25nKHN0cmluZykpIHsKICAgICAgICBsb2Nfc3RhcnQgPC0gc3RyX2xvY2F0ZShzdHJpbmdbW2ldXSwgc3RhcnQpIAogICAgICAgIGxvY19lbmQgPC0gc3RyX2xvY2F0ZShzdHJpbmdbW2ldXSwgZW5kKQogICAgICAgIG91dHB1dFtbaV1dIDwtIHN0cl9zdWIoc3RyaW5nW1tpXV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGxvY19zdGFydFsxLDFdICsgOCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGxvY19lbmRbMSwxXSAtIDMpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICB9CiAgIG91dHB1dAp9CmtpY2tzdGFydGVyJGNhdGVnb3J5IDwtIGV4dHJhY3RfY2F0ZWdvcnkoa2lja3N0YXJ0ZXIkY2F0ZWdvcnkpCgpgYGAKCkV4dHJhY3QgY3JlYXRvcgp7InVybHMiOnsid2ViIjp7InVzZXIiOiJodHRwczovL3d3dy5raWNrc3RhcnRlci5jb20vcHJvZmlsZS9pdGhhcXVhbGFicyJ9LCJhcGkiOnsidXNlciI6Imh0dHBzOi8vYXBpLmtpY2tzdGFydGVyLmNvbS92MS91c2Vycy8yNDY0MTA4MTg/c2lnbmF0dXJlPTE1MDI5NDkxMDUuYmU3MWE1YzgxNjk2MTdmOWZhZWVjMzliMzg0YjcxNWIwZGNiYmRjZCJ9fSwiaXNfcmVnaXN0ZXJlZCI6dHJ1ZSwibmFtZSI6IkNocmlzdG9waGVyIFxcIk1pY2hhZWxcXCIgSGFsbCIsImlkIjoyNDY0MTA4MTgsImF2YXRhciI6eyJzbWFsbCI6Imh0dHBzOi8va3NyLXVnYy5pbWdpeC5uZXQvYXNzZXRzLzAwNy8wMTgvNDk0L2U5NmNjNjZjYTYzOWRmYzkwNTVkZjQ4NTA1OTUyMTA0X29yaWdpbmFsLmpwZz93PTE2MCZoPTE2MCZmaXQ9Y3JvcCZ2PTE0NjE0Mjg2MTcmYXV0bz1mb3JtYXQmcT05MiZzPTk0NzIzMzc3MGE0NjNmMzgzYTZlMDJjZTlkZTkyN2FiIiwidGh1bWIiOiJodHRwczovL2tzci11Z2MuaW1naXgubmV0L2Fzc2V0cy8wMDcvMDE4LzQ5NC9lOTZjYzY2Y2E2MzlkZmM5MDU1ZGY0ODUwNTk1MjEwNF9vcmlnaW5hbC5qcGc/dz00MCZoPTQwJmZpdD1jcm9wJnY9MTQ2MTQyODYxNyZhdXRvPWZvcm1hdCZxPTkyJnM9MjIzNWEyNDU2OGVjOGFhZGIzNTM3MzE4NDkzM2EzNDciLCJtZWRpdW0iOiJodHRwczovL2tzci11Z2MuaW1naXgubmV0L2Fzc2V0cy8wMDcvMDE4LzQ5NC9lOTZjYzY2Y2E2MzlkZmM5MDU1ZGY0ODUwNTk1MjEwNF9vcmlnaW5hbC5qcGc/dz0xNjAmaD0xNjAmZml0PWNyb3Amdj0xNDYxNDI4NjE3JmF1dG89Zm9ybWF0JnE9OTImcz05NDcyMzM3NzBhNDYzZjM4M2E2ZTAyY2U5ZGU5MjdhYiJ9LCJzbHVnIjoiaXRoYXF1YWxhYnMifQoKYGBge3J9CmV4dHJhY3RfY3JlYXRvciA8LSBmdW5jdGlvbihzdHJpbmcpIHsKICAgIG91dHB1dCA8LSB2ZWN0b3IoImNoYXJhY3RlciIsIGxlbmd0aChzdHJpbmcpKQogICAgc3RhcnQgPC0gJyJuYW1lIjoiJwogICAgZW5kIDwtICciaWQiJwogICAgZm9yIChpIGluIHNlcV9hbG9uZyhzdHJpbmcpKSB7CiAgICAgICAgbG9jX3N0YXJ0IDwtIHN0cl9sb2NhdGUoc3RyaW5nW1tpXV0sIHN0YXJ0KSAKICAgICAgICBsb2NfZW5kIDwtIHN0cl9sb2NhdGUoc3RyaW5nW1tpXV0sIGVuZCkKICAgICAgICBvdXRwdXRbW2ldXSA8LSBzdHJfc3ViKHN0cmluZ1tbaV1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChsb2Nfc3RhcnRbMSwxXSArIDgpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChsb2NfZW5kWzEsMV0gLSAzKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgfQogICBvdXRwdXQKfQpraWNrc3RhcnRlciRjcmVhdG9yIDwtIGV4dHJhY3RfY3JlYXRvcihraWNrc3RhcnRlciRjcmVhdG9yKQoKa2lja3N0YXJ0ZXIgJT4lCiAgICBzZWxlY3QoY3JlYXRvcikKYGBgCgpFeHRyYWN0IGxvY2F0aW9uCnsiY291bnRyeSI6IlVTIiwidXJscyI6eyJ3ZWIiOnsiZGlzY292ZXIiOiJodHRwczovL3d3dy5raWNrc3RhcnRlci5jb20vZGlzY292ZXIvcGxhY2VzL2F0bGFudGEtZ2EiLCJsb2NhdGlvbiI6Imh0dHBzOi8vd3d3LmtpY2tzdGFydGVyLmNvbS9sb2NhdGlvbnMvYXRsYW50YS1nYSJ9LCJhcGkiOnsibmVhcmJ5X3Byb2plY3RzIjoiaHR0cHM6Ly9hcGkua2lja3N0YXJ0ZXIuY29tL3YxL2Rpc2NvdmVyP3NpZ25hdHVyZT0xNTAyOTI0NTk3LmNiM2ZiZjVmYmU5MTU0ZGRmMDRkODVlN2JlODc5ZTQ0MDNlM2ZkOTgmd29lX2lkPTIzNTcwMjQifX0sIm5hbWUiOiJBdGxhbnRhIiwiZGlzcGxheWFibGVfbmFtZSI6IkF0bGFudGEsIEdBIiwic2hvcnRfbmFtZSI6IkF0bGFudGEsIEdBIiwiaWQiOjIzNTcwMjQsInN0YXRlIjoiR0EiLCJ0eXBlIjoiVG93biIsImlzX3Jvb3QiOmZhbHNlLCJzbHVnIjoiYXRsYW50YS1nYSJ9CgpgYGB7cn0KZXh0cmFjdF9sb2NhdGlvbiA8LSBmdW5jdGlvbihzdHJpbmcpIHsKICAgIG91dHB1dCA8LSB2ZWN0b3IoImNoYXJhY3RlciIsIGxlbmd0aChzdHJpbmcpKQogICAgc3RhcnQgPC0gJyJkaXNwbGF5YWJsZV9uYW1lIjoiJwogICAgZW5kIDwtICcic2hvcnRfbmFtZSInCiAgICBmb3IgKGkgaW4gc2VxX2Fsb25nKHN0cmluZykpIHsKICAgICAgICBsb2Nfc3RhcnQgPC0gc3RyX2xvY2F0ZShzdHJpbmdbW2ldXSwgc3RhcnQpIAogICAgICAgIGxvY19lbmQgPC0gc3RyX2xvY2F0ZShzdHJpbmdbW2ldXSwgZW5kKQogICAgICAgIG91dHB1dFtbaV1dIDwtIHN0cl9zdWIoc3RyaW5nW1tpXV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGxvY19zdGFydFsxLDFdICsgMjApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChsb2NfZW5kWzEsMV0gLSAzKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgfQogICBvdXRwdXQKfQpraWNrc3RhcnRlciRsb2NhdGlvbiA8LSBleHRyYWN0X2xvY2F0aW9uKGtpY2tzdGFydGVyJGxvY2F0aW9uKQoKa2lja3N0YXJ0ZXIgJT4lCiAgICBzZWxlY3QobG9jYXRpb24pCmBgYAoKRXh0cmFjdCBwcm9maWxlIC0gTmV2ZXJtaW5kLCBnZXQgcmlkIG9mIGl0IQp7ImJhY2tncm91bmRfaW1hZ2Vfb3BhY2l0eSI6MC44LCJzaG91bGRfc2hvd19mZWF0dXJlX2ltYWdlX3NlY3Rpb24iOnRydWUsImxpbmtfdGV4dF9jb2xvciI6bnVsbCwic3RhdGVfY2hhbmdlZF9hdCI6MTQ4MzE3MDg2NCwiYmx1cmIiOm51bGwsImJhY2tncm91bmRfY29sb3IiOm51bGwsInByb2plY3RfaWQiOjI4MTY0MTYsIm5hbWUiOm51bGwsImZlYXR1cmVfaW1hZ2VfYXR0cmlidXRlcyI6eyJpbWFnZV91cmxzIjp7ImRlZmF1bHQiOiJodHRwczovL2tzci11Z2MuaW1naXgubmV0L2Fzc2V0cy8wMTUvMDI1LzYzNC83NzgzMjNlMzI1ZTQ5ZTFjZjQ3Y2ViYzQ5ZTQyMGIwMF9vcmlnaW5hbC5qcGc/Y3JvcD1mYWNlcyZ3PTE1NTImaD04NzMmZml0PWNyb3Amdj0xNDgzMTc1MTIwJmF1dG89Zm9ybWF0JnE9OTImcz05ZGZkNmM4MjQyNDc3Y2Y4MmM4ZThjMDNkMDgwMWE0NSIsImJhc2ViYWxsX2NhcmQiOiJodHRwczovL2tzci11Z2MuaW1naXgubmV0L2Fzc2V0cy8wMTUvMDI1LzYzNC83NzgzMjNlMzI1ZTQ5ZTFjZjQ3Y2ViYzQ5ZTQyMGIwMF9vcmlnaW5hbC5qcGc/Y3JvcD1mYWNlcyZ3PTU2MCZoPTMxNSZmaXQ9Y3JvcCZ2PTE0ODMxNzUxMjAmYXV0bz1mb3JtYXQmcT05MiZzPTI4Y2E3NWQ3NWFjOTFlNzVjYmJkY2RkZmEyYzYwNDJlIn19LCJsaW5rX3VybCI6bnVsbCwic2hvd19mZWF0dXJlX2ltYWdlIjpmYWxzZSwiaWQiOjI4MTY0MTYsInN0YXRlIjoiaW5hY3RpdmUiLCJ0ZXh0X2NvbG9yIjpudWxsLCJsaW5rX3RleHQiOm51bGwsImxpbmtfYmFja2dyb3VuZF9jb2xvciI6bnVsbH0KCmBgYHtyLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpleHRyYWN0X3Byb2ZpbGUgPC0gZnVuY3Rpb24oc3RyaW5nKSB7CiAgICBvdXRwdXQgPC0gdmVjdG9yKCJjaGFyYWN0ZXIiLCBsZW5ndGgoc3RyaW5nKSkKICAgIHN0YXJ0IDwtICciZGlzcGxheWFibGVfbmFtZSI6IicKICAgIGVuZCA8LSAnInNob3J0X25hbWUiJwogICAgZm9yIChpIGluIHNlcV9hbG9uZyhzdHJpbmcpKSB7CiAgICAgICAgbG9jX3N0YXJ0IDwtIHN0cl9sb2NhdGUoc3RyaW5nW1tpXV0sIHN0YXJ0KSAKICAgICAgICBsb2NfZW5kIDwtIHN0cl9sb2NhdGUoc3RyaW5nW1tpXV0sIGVuZCkKICAgICAgICBvdXRwdXRbW2ldXSA8LSBzdHJfc3ViKHN0cmluZ1tbaV1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChsb2Nfc3RhcnRbMSwxXSArIDIwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAobG9jX2VuZFsxLDFdIC0gMykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgIH0KICAgb3V0cHV0Cn0Ka2lja3N0YXJ0ZXIkcHJvZmlsZSA8LSBleHRyYWN0X3Byb2ZpbGUoa2lja3N0YXJ0ZXIkcHJvZmlsZSkKCmtpY2tzdGFydGVyICU+JQogICAgc2VsZWN0KHByb2ZpbGUpCmBgYApBbmQgbm93IGNvbnZlcnQgYSBjb3VwbGUgb2YgdGhvc2UgcmVjZW50bHkgZXh0cmFjdGVkIGNoYXJhY3RlciBzdHJpbmdzIHRvIGZhY3RvcnMKYGBge3J9CmtpY2tzdGFydGVyJGNhdGVnb3J5IDwtIGFzLmZhY3RvcihraWNrc3RhcnRlciRjYXRlZ29yeSkKa2lja3N0YXJ0ZXIkbG9jYXRpb24gPC0gYXMuZmFjdG9yKGtpY2tzdGFydGVyJGxvY2F0aW9uKQpraWNrc3RhcnRlciRpZCA8LSBhcy5jaGFyYWN0ZXIoa2lja3N0YXJ0ZXIkaWQpCnN1bW1hcnkoa2lja3N0YXJ0ZXIpCgoKYGBgCgpTbyBJIHdhbnQgdG8gcnVuIGJhY2sgdGhyb3VnaCB3aGF0IEkgZGlkIGluIHN0YWdlIDEsIHdoaWNoIEkgZmVlbCBJIGhhdmUgbm93IGNvbXBsZXRlZC4KQSBjb3VwbGUgbGV2ZWxzIHRvIGZvY3VzIG9uOgpUb3AgbGV2ZWw6IEkgdGhpbmsgSSBzdHVjayB3aXRoIHRoZSBiYXNpYyBhY3Rpdml0aWVzIHRoYXQgSSBzdGFydGVkIHdpdGgsIGJ1dCBJIHdpbGwgdmVyaWZ5IHRoYXQuClNlY29uZCBsZXZlbDogSSB0aGluayB0aGV5IHdlcmUgYWxsIHByZXR0eSBzdHJhaWdodCBmb3J3YXJkLCBleGNlcHQgZm9yIHRoZSBjbGVhbmluZyBwYXJ0LiBJIHdhbnQgdG8gYmUgc3VyZSBhbmQgb3V0bGluZSBhbGwgb2YgdGhlIHRoaW5ncyBJIGRpZCBmb3IgY2xlYW5pbmcgc28gdGhhdCBJIGNhbiBnZW5lcmFsaXplIGEgbGl0dGxlIGJpdC4KQW5kIEkgd2FudCB0byBiZSBzdXJlIHRoYXQgSSBkaWQgaW4gZmFjdCBjb21wbGV0ZSB0aGUgb3RoZXIgc3RhZ2VzLiBJIGFsc28gd2FudCB0byBzZWUgaWYgdGhlcmUgd2VyZSBhbnkgc3RlcHMgd29ydGggbGlzdGluZyBmb3IgYW55IG9mIHRob3NlLiBBbHNvLCB3b3VsZCBhbnl0aGluZyBoYXZlIGJlbmVmaXR0ZWQgZnJvbSBhIG1vcmUgZm9ybWFsIHdhbGsgdGhyb3VnaCB0aGUgaXRlcmF0aW9uIHByb2Nlc3M/CgpUbyBiZWdpbjogTXkgaW5pdGlhbCBnb2FscyBmb3IgdGhpbmdzIHRvIGFjY29tcGxpc2ggaW4gU3RhZ2UgMToKSW5pdGlhbCB0aG91Z2h0cyBvbiB3aGF0IG5lZWRzIHRvIGJlIGFjY29tcGxpc2hlZCBkdXJpbmcgdGhpcyBzdGFnZQoxLiBBc2sgYSBxdWVzdGlvbgoyLiBDb2xsZWN0IGRhdGEKMy4gSW5zcGVjdCB0aGUgZGF0YQo0LiBSZWZpbmUgYW5kIHNoYXJwZW4gdGhlIHF1ZXN0aW9uIChub3QgcmVhbGx5IGEgZGlzdGluY3Qgc3RvcCAtIGVuY29tcGFzc2VkIGluIHRoZSBpdGVyYXRpb24gY3ljbGUpCjUuIENsZWFuIGFuZCBUaWR5IHRoZSBkYXRhCgpJbnNwZWN0OgpoZWFkCm5fZGlzdGluY3QKZGltCnN0cgpjb2xuYW1lcy9uYW1lcwpzdW1tYXJ5Cm9iamVjdC5zaXplClBsb3R0ZWQgc29tZSBkYXRlcwpTb21lIGdyb3VwZWQgc3VtbWFyaWVzCgpDbGVhbiBhbmQgVGlkeToKQ29udmVydGVkIERhdGVzCkNoYXJhY3RlcnMgdG8gZmFjdG9ycwpDaGVjayBmb3IgYW5kIGRlYWwgd2l0aCBtaXNzaW5nIGRhdGEKRXhwbG9yZSBhbmQgZGVhbCB3aXRoIG91dGxpZXJzClJlbW92ZSB1bm5lY2Vzc2FyeSBkYXRhIChnZW5lcmFsaXplZCBmcm9tIHVzZWxlc3MgY29sdW1ucyBhbmQgbGl2ZS9vbmdvaW5nIGNhc2VzKQpNYW5pcHVsYXRlIGNoYXJhY3RlciBzdHJpbmdzCgpTbyBJIHRoaW5rIHRoYXQgdGhlIGluc3BlY3Qgc3RlcHMgYW5kIHRoZSBjbGVhbi90aWR5IHN0ZXAgY291bGQgcmVhbGx5IGJlbmVmaXQgZnJvbSBhIHN0YXRlZCBnb2FsIGF0IHRoZSBiZWdpbm5pbmcuIFRoaXMgd291bGQgYWxsb3cgdXNlIG9mIHRoZSBpdGVyYXRpb24gY3ljbGUgYW5kIG1vcmUgY2xlYXJseSBkZWZpbmUgdGhlIHdvcmsgdG8gYmUgZG9uZS4KCkdvYWwgZm9yIEluc3BlY3Q6IFRvIGRldmVsb3AgYW4gaWRlYSBvZiB0aGUgcG90ZW50aWFsIHVzZWZ1bG5lc3Mgb2YgdGhlIGRhdGFzZXQgYW5kIGlkZW50aWZ5IHByb2JsZW1zIHdpdGggdGhlIGRhdGFzZXQuCgpHb2FsIGZvciBDbGVhbiBhbmQgVGlkeTogVG8gcHV0IHRoZSBkYXRhc2V0IGludG8gYSB1c2VmdWwgZm9ybWF0IGFuZCBmaXggcHJvYmxlbXMgd2l0aCB0aGUgZGF0YXNldC4KCkkgbGlrZSBpdC4gSSBjb3VsZCByZXZpc2l0IHRoZXNlIG9uIHRoZSBuZXh0IHBhc3MuCgpTbyBzaG91bGQgSSBnbyB3aXRoIGEgZGlmZmVyZW50IG5vdGVib29rIGZvciB0aGUgbmV4dCBzdGFnZT8KTmFoCgojIyBTdGFnZSAyOiBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpCg==